Skip to content

Do not check IsEmpty for every item in ConcurrentBag.Clear - #704

Merged
SimonCropp merged 1 commit into
mainfrom
perf/concurrentbag-clear
Oct 12, 2026
Merged

SimonCropp merged 1 commit into
mainfrom
perf/concurrentbag-clear

Conversation

@SimonCropp

Copy link
Copy Markdown
Owner

The ConcurrentBag<T>.Clear polyfill (.NET Framework / netstandard2.0) checked IsEmpty before every TryTake. On .NET Framework IsEmpty freezes the bag under its global lock, so it costs more than the TryTake it guards.

TryTake already returns false once the bag is empty, so the loop is now:

while (target.TryTake(out _))
{
}

Same result, including when other threads add or take concurrently: both versions stop the first time the bag is observed empty.

Measurements

net48, Release, x64, Stopwatch around Clear only, best of 7, microseconds per call:

Items Before After
0 0.09 0.24
10 1.23 1.01
1,000 82.3 37.0
100,000 7,281 3,032

Clearing an already empty bag is about 0.15 us slower, because a failing TryTake (which tries to steal from other threads' lists) costs more than IsEmpty. Guarding with one IsEmpty up front would fix that case and make every other case pay for it, so I left it out.

Tests

Added to PolyfillTests_ConcurrentBag.cs: clearing bags of 0, 1, 2 and 1,000 items (IsEmpty, Count, ToArray, TryTake, TryPeek afterwards, clearing twice, and reuse after clearing); a bag filled from four threads, so that items live in several thread-local lists; null and default items.

TryTake returns false once the bag is empty, so the IsEmpty check before every TryTake is redundant, and IsEmpty takes the bag's global lock.
@SimonCropp SimonCropp modified the milestones: 11.4.4, 11.4.5 Oct 12, 2026
@SimonCropp
SimonCropp merged commit 65f163c into main Oct 12, 2026
7 checks passed
@SimonCropp
SimonCropp deleted the perf/concurrentbag-clear branch October 12, 2026 12:10
This was referenced Oct 12, 2026
This was referenced Oct 14, 2026
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