Skip to content

perf(Signal): speed up multicast dispatch; chore: normalise line endings to LF#17

Merged
glennawatson merged 2 commits into
mainfrom
perf/signal-multicast-dispatch
Jun 2, 2026
Merged

perf(Signal): speed up multicast dispatch; chore: normalise line endings to LF#17
glennawatson merged 2 commits into
mainfrom
perf/signal-multicast-dispatch

Conversation

@glennawatson
Copy link
Copy Markdown
Contributor

Two independent changes (squash-merge will keep them as one; the commits are atomic if you prefer rebase):


perf(Signal): typed observer/action fields for multicast dispatch

Signal<T>.SignalSubscription stored its target in a single object _target and, on every dispatched callback, did an is Action<T> type-test plus an (IObserver<T>)_target cast. On the multicast hot path (DispatchSubscriptions) that isinst+castclass runs once per observer per value.

This switches the subscription to two typed fields — IObserver<T>? _observer and Action<T>? _action — so dispatch branches on a cheap null check. OnError/OnCompleted collapse to _observer?.On…(…). The single-observer/single-action fast paths are unchanged.

Results

ShortRun, net10.0, 1024 emits fanned out to N observers (new SubjectMulticastBenchmarks):

Signal multicast (1024 emits) Before After System.Reactive R3
×4 observers 6.98 µs 5.76 µs (−17.5%) 5.25 µs 8.71 µs
×8 observers 12.11 µs 10.52 µs (−13.2%) 9.88 µs 17.0 µs

Signal<T> goes from ~24–28% behind System.Reactive.Subject<T> to ~6–9%, stays well ahead of R3, and keeps the lowest allocation of the three. Cost is +8 bytes per SignalSubscription (one extra reference field).

All 221 ReactiveUI.Primitives.Tests pass (net9.0); behaviour preserved (action subscriptions still ignore OnError/OnCompleted, now via the null _observer).


chore: normalise line endings to LF

.gitattributes forced eol=crlf on checkout while storing LF blobs, and even marked *.sh eol=crlf (which corrupts shell scripts). Switched the global rule to plain * text=auto and dropped the forced eol=crlf from *.sln, *.sh, *.cmd, *.bat, so working trees check out LF on every platform.

git add --renormalize . confirmed every blob was already LF, so the only committed change is .gitattributes itself.

The repo forced eol=crlf on checkout while storing LF blobs; *.sh was even
marked eol=crlf, which corrupts shell scripts. Switch to plain text=auto so
working trees check out LF on every platform. All blobs were already LF, so
git add --renormalize touched nothing but .gitattributes.
@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud Bot commented Jun 2, 2026

@codecov
Copy link
Copy Markdown

codecov Bot commented Jun 2, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 91.56%. Comparing base (d8c6eda) to head (4decf60).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main      #17      +/-   ##
==========================================
+ Coverage   91.53%   91.56%   +0.02%     
==========================================
  Files         398      399       +1     
  Lines       15481    15546      +65     
  Branches     2231     2248      +17     
==========================================
+ Hits        14171    14235      +64     
+ Misses        990      989       -1     
- Partials      320      322       +2     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@glennawatson glennawatson merged commit 0e1200d into main Jun 2, 2026
14 checks passed
@glennawatson glennawatson deleted the perf/signal-multicast-dispatch branch June 2, 2026 07:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant