If I have a ConcurrentDictionary
instance, does it matter whether I use the Count
property or LINQ's Any()
? I'd rather write dict.Any()
instead of dict.Count > 0
as I think Any()
is more descriptive.
I'm only concerned about correctness, not performance. The use case is
void process()
{
if (concurrentDictionary.Count <= 0) // or !Any() ?
return; // dictionary is empty, nothing to do
// ...
}
The question Are IEnumerable Linq methods thread-safe? addresses the fact that the IEnumerable methods on LINQ queries are not thread safe without a specific lock being kept protecting the collection.
You can look at the reference code for ConcurrentDictionary to see that the enumerator does not provide a thread-safe snapshot. Additional the MSDN Documentation for ConcurrentDictionary.GetEnumerator states:
The enumerator returned from the dictionary is safe to use concurrently with reads and writes to the dictionary, however it does not represent a moment-in-time snapshot of the dictionary. The contents exposed through the enumerator may contain modifications made to the dictionary after GetEnumerator was called
The Count property takes a full lock on the dictionary and returns a consistent result.
So depending on whether you want to take a lock on the dictionary to run Any()
it is probably cleaner to check for Count > 0
.
You will have to benchmark them, because the Any()
is something like
using (IEnumerator<TSource> enumerator = source.GetEnumerator())
{
if (enumerator.MoveNext())
{
return true;
}
}
return false;
so it requires enumeration, that for ConcurrentDictionary
is something complex, but even the Count
of ConcurrentDictionary
isn't cached and it seems to be pretty complex.
I'll add that the Count
must still traverse some internal structures (as in an array of) aquiring a lock on the whole dictionary, while the Any()
will stop at the first non-empty bucket. I'll say that for a big dictionary, Count
is slower, while for a small one it is faster.
Correction: the Count
aquires a lock on all the dictionary before counting. it does call this.AcquireAllLocks()
.
Remember that the result of both method could be falsified before the methods return, because hey... concurrency! :-)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With