Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is multi-level ConcurrentDictionary still thread-safe?

I have four level data structure defined like this:

Dictionary<Type1, Dictionary<Type2, Dictionary<Type3, List<Type4>>>>

The whole thing is encapsulated in a class which also maintains thread-safety. Currently it just locks whole collection while it reads/manipulates the data (reading is by orders of magnitude more common than writing).

I was thinking of replacing the Dictionary with ConcurrentDictionary and List with ConcurrentBag (its items don't have to be ordered).

If I do so, can I just eliminate the locks and be sure the concurrent collections will do their job correctly?

like image 529
Matěj Zábský Avatar asked Dec 28 '22 01:12

Matěj Zábský


2 Answers

I'm nearly a year late to the question.. but just in case anyone finds themselves in a similar position to Matěj Zábský, ask yourself:

Can you use a Dictionary<Tuple<Type1, Type2, Type3>, List<Type4>> instead?

Considerably easier to work with, and considering that hash tables (ie Dictionaries) are O(1) data structures with a somewhat hefty constant component (even more so if you move to a ConcurrentDictionary) it'd likely perform faster too. It'd also use less memory, and be pretty trivial to convert to a ConcurrentDictionary.

Of course if you need to enumerate all of a given Type2 for a given Type1 key, the nested dictionaries is possibly the way to go. But is that a requirement?

like image 187
Mania Avatar answered Jan 13 '23 18:01

Mania


The concurrent collections will prevent data corruption and crashes, but the code won't be semantically equivalent to your current one. For example, if you iterate one of the concurrent dictionaries, some of the items may belong to different updates:

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.

If you want to maintain the exact behavior you have now, yet save on the cost of locking, you may want to lock with ReaderWriterLockSlim which is especially suited for cases with more reads than writes.

like image 42
Ohad Schneider Avatar answered Jan 13 '23 17:01

Ohad Schneider