Skip to content

Reduce subscriber contention with bounded spinning - #18

Merged
prezaei merged 8 commits into
mainfrom
v2
Sep 12, 2026
Merged

prezaei merged 8 commits into
mainfrom
v2

Conversation

@prezaei

@prezaei prezaei commented Nov 28, 2022

Copy link
Copy Markdown
Member

When subscribers contend for the read lock, blocking Dequeue currently yields and progresses to semaphore waits of up to 10 ms. Use bounded SpinWait retries before a 5 ms semaphore wait, resetting the spin budget after waiting. TryDequeue still makes one read-lock attempt, and the existing publisher/subscriber crash recovery remains intact. Also observe cancellation while waiting for a publisher to finish writing a reserved message.

Add eight regression cases covering contended reads, expired read locks, cancellation, and exactly-once delivery with concurrent publishers and subscribers. Add a reproducible concurrent-subscriber benchmark, support benchmark selection from the command line, and update existing benchmark jobs to .NET 10. This branch includes current main and the queue lifetime fix.

Validation:

The benchmark refresh corrects the enqueue operation count and ensures the ring-wrap workload actually crosses the buffer boundary. All seven benchmarks were run directly on an Apple M5 Max with .NET 10, three warm-up iterations, and eight measured iterations. The README includes the native Mac results and full reports; its historical Windows and Linux measurements are unchanged.

Native Mac workload Mean per operation
Enqueue, 3 bytes 182.3 ns
Enqueue + dequeue, 3 bytes, reused buffer 210.0 ns
Enqueue + dequeue, 3 bytes, new result array 214.9 ns
Enqueue + dequeue, 50 bytes, reused buffer 214.6 ns
Enqueue + dequeue, 50 bytes, ring-wrap workload 223.8 ns
Concurrent delivery, 8 bytes, 1 subscriber 246.5 ns
Concurrent delivery, 8 bytes, 4 subscribers 344.7 ns

These are in-process microbenchmarks. Concurrent delivery measures amortized time per message, including worker startup and completion, rather than individual message latency. Earlier native Mac comparisons against main measured 253.3 → 241.0 ns with one subscriber and 1,505.4 → 342.0 ns with four; those used only three measured iterations and the contended baseline was noisy.

Reproduce all cases from the repository root:

dotnet run --project src/Interprocess.Benchmark -c Release -- --filter '*' --warmupCount 3 --iterationCount 8 --artifacts BenchmarkDotNet.Artifacts

@prezaei prezaei changed the title Faster Susbscriber Reduce subscriber contention with bounded spinning Sep 12, 2026
@prezaei
prezaei merged commit e0fd9c3 into main Sep 12, 2026
3 checks passed
@prezaei
prezaei deleted the v2 branch September 12, 2026 23:59
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