91

I'm always confused on which one of these to pick. As I see it I use Dictionary over List if I want two data types as a Key and Value so I can easily find a value by its key but I am always confused if I should use a ConcurrentDictionary or Dictionary?

Before you go off at me for not putting much research in to this I have tried, but it seems google hasn't really got anything on Dictionary vs ConcurrentDictionary but has something on each one individually.

I have asked a friend this before but all they said is: "use ConcurrentDictionary if you use your dictionary a lot in code" and I didn't really want to pester them in to explaining it in larger detail. Could anyone expand on this?

Luiso
  • 4,173
  • 2
  • 37
  • 60
Ashkru
  • 1,495
  • 1
  • 17
  • 26
  • So, after having looked through information on each of those objects individually, how did that fail to answer your question of when you should use each one? If you know when you should use a `Dictionary` and when you should use a `ConcurrentDictionary`, given that you say you've already found that information, then you know when you should use one over the other. – Servy Feb 02 '17 at 22:10
  • The name kind of explains it self. You use a `ConcurrentDictionary` when you need Concurrent access to a Dictionary. – Scott Chamberlain Feb 02 '17 at 22:10
  • 3
    use ConcurrentDictionary if you'll be accessing the dictionary from multiple threads. That's what the whole `System.Collections.Concurrent` namespace is for – Jonesopolis Feb 02 '17 at 22:11
  • The thing to search for is "thread safety". – Matthew Cawley Feb 02 '17 at 22:14
  • @Servy so you are saying that if they know what you already knew they would not have to ask the question. However they do not know this yet, and so are asking. (reading two definitions does not always help you know the difference) – ctrl-alt-delor Feb 02 '17 at 22:15
  • 1
    The answers below are kind of incorrect, by referring to 'threads'. `Task`s should work with `ConcurrentDictionary` too. – hyankov Feb 02 '17 at 22:16
  • @richard No, I'm saying that if they already knew *what they said in the question they already knew* then they'd know the answer to the question. The readily avaliable information on each type is going to make the differences very readily apparent. If there's some specific source of confusion after having looked through the two then there'd need to be more than, "tell me the difference because I couldn't be bothered to look" in a question, laying out what they saw, and why the differences weren't apparent. – Servy Feb 02 '17 at 22:16
  • @Servy ah I see. We can see from your reasoning that you are wrong, because the question was asked. – ctrl-alt-delor Feb 02 '17 at 22:18
  • @richard That's a false reasoning. That they choose not to do their research or look at the differences between the two types doesn't mean that they couldn't, just that the *didn't*. One can in fact ask a question that you know the answer to, or that you could trivially find an answer to. Assuming that it's impossible to ask a question that you could trivially find the answer to is a false assumption. – Servy Feb 02 '17 at 22:19
  • My assumption is that the questioner probably, inadvertently, filtered out words that they did not understand (such as concurrent). Therefore we need to help with the meaning of these words. Not just say use “concurrent what you need concurrency” — as Scott said. As this is a linguistic truism, that can be derived from the rules of English grammar. We probably need to explain what concurrent means, especially in the context of programming. – ctrl-alt-delor Feb 02 '17 at 22:25
  • @richard A simple web search on that term would provide the definition, if they don't in fact understand the word. Although if they stated that that was what they didn't understand, it would make the question at least better than it is now, albeit it still not a suitable question as that more detailed question is itself readily available with simple research. But the point is that we can't just sit here trying to guess at what they do and don't understand. They need to ask a more specific question explaining what aspects of this decision they don't understand, hence my original question. – Servy Feb 02 '17 at 22:44
  • @Servy yes I agree, and think that we should refrain from answering until the question is clear, up until then we need to discover what the question is, buy asking for clarification. – ctrl-alt-delor Feb 02 '17 at 22:56

5 Answers5

111

"Use ConcurrentDictionary if you use your dictionary in a lot in code" is kind of vague advice. I don't blame you for the confusion.

ConcurrentDictionary is primarily for use in an environment where you're updating the dictionary from multiple threads (or async tasks). You can use a standard Dictionary from as much code as you like if it's from a single thread ;)

If you look at the methods on a ConcurrentDictionary, you'll spot some interesting methods like TryAdd, TryGetValue, TryUpdate, and TryRemove.

For example, consider a typical pattern you might see for working with a normal Dictionary class.

// There are better ways to do this... but we need an example ;)
if (!dictionary.ContainsKey(id))
    dictionary.Add(id, value);

This has an issue in that between the check for whether it contains a key and calling Add a different thread could call Add with that same id. When this thread calls Add, it'll throw an exception. The method TryAdd handles that for you and will return a true/false telling you whether it added it (or whether that key was already in the dictionary).

So unless you're working in a multi-threaded section of code, you probably can just use the standard Dictionary class. That being said, you could theoretically have locks to prevent concurrent access to a dictionary; that question is already addressed in "Dictionary locking vs. ConcurrentDictionary".

Jeff B
  • 8,572
  • 17
  • 61
  • 140
  • 3
    Thank you for the answer, it helped a lot. Would using a ConcurrentDictionary everywhere even if its coming from a single thread be such a bad thing? – Ashkru Feb 02 '17 at 22:50
  • 2
    Can you use non concurrent form, if you do the writing before creating threads (one multi-threading, only do reads)? I would imagine this is faster, and can't not see how it could break (until you did something silly, like write to it). – ctrl-alt-delor Feb 02 '17 at 22:58
  • 1
    There's probably no problem with using `ConcurrentDictionary`, but I imagine there'd be at least some overhead that depending on how the dictionary is used could be a bottleneck. If you'd like to compare the source to see what's happening, check out the source for [ConcurrentDictionary.TryAddInternal()](https://referencesource.microsoft.com/#mscorlib/system/Collections/Concurrent/ConcurrentDictionary.cs,bc495056297a0851) and [Dictionary.Insert()](https://referencesource.microsoft.com/#mscorlib/system/collections/generic/dictionary.cs,fd1acf96113fbda9). – Jeff B Feb 02 '17 at 22:58
  • I guess the main purpose of this is I don't exactly understand when a Solution is multi-threaded, does this specifically mean its multi-threaded if a new thread is programming created and started or are there other things that make an application multi threaded? I saw him say about Async Tasks, is there anything else? – Ashkru Feb 02 '17 at 23:01
  • There's a lot of ways to do threading. A bit too much to cover here ;) – Jeff B Feb 02 '17 at 23:06
  • @JeffBridgman do you mean if I use `async` methods with `await` inside I should use `ConcurrentDictionary` there? – Konrad Jun 26 '18 at 08:44
  • 1
    @Konrad It really depends on your specific code and whether the dictionary is accessed from multiple thread (in a way that could produce a race condition) so the best answer I can give is "maybe" :P – Jeff B Jun 26 '18 at 16:33
  • @JeffBridgman oh so as long as it doesn't crash and produce race condition I will stick with Dictionary. – Konrad Jun 26 '18 at 19:23
11

The biggest reason to use ConcurrentDictionary over the normal Dictionary is thread safety. If your application will get multiple threads using the same dictionary at the same time, you need the thread-safe ConcurrentDictionary, this is particularly true when these threads are writing to or building the dictionary.

The downside to using ConcurrentDictionary without the multi-threading is overhead. All those functions that allow it to be thread-safe will still be there, all the locks and checks will still happen, taking processing time and using extra memory.

Andrew
  • 1,544
  • 1
  • 18
  • 36
  • 2
    Are there any downsides to `ConcurrentDictionary` with single-threaded code? – Aaron Franke Mar 22 '19 at 06:14
  • 5
    @AaronFranke Overhead, the functionality that allows for the thread safety will still be there, the checks involved will still happen, so it will be a larger object and take more processing to work with. Also others who read the code will go looking for the threading and be confused by it possibly. – Andrew Mar 22 '19 at 13:58
6

ConcurrentDictionary is useful when you need to access a dictionary across multiple threads (i.e. multithreading). Vanilla Dictionary objects do not possess this capability and therefore should only be used in a single-threaded manner.

Woody1193
  • 7,252
  • 5
  • 40
  • 90
  • Would using a ConcurrentDictionary everywhere even if its coming from a single thread be such a bad thing? – Ashkru Feb 02 '17 at 22:51
  • 1
    No, because you'd confuse anyone reading your code later if you don't plan on multithreading your program. Also, I would expect some additional overhead in any concurrent data structure because access privileges have to be managed across multiple threads – Woody1193 Feb 02 '17 at 22:53
  • 2
    You say no then go on like its a bad thing, is it a bad thing? The reason I am asking is because it currently doesn't get accessed from other threads than the main thread but it could in the future. Is it worth just using a Concurrent to handle all ways or changing my code if I do decide to implement multi threading? – Ashkru Feb 02 '17 at 22:59
  • 2
    I don't know what your specific needs are. I'm simply demonstrating the pros and cons of using them. If you think you might need to multithread your code in the future and your dictionary might be used across multiple threads then using a `ConcurrentDictionary` would be a valid design choice. However, if you don't plan on doing that then you should avoid it because that data structure would not be best-suited to your requirements – Woody1193 Feb 02 '17 at 23:02
5

A ConcurrentDictionary is useful when you want a high-performance dictionary that can be safely accessed by multiple threads concurrently. Compared to a standard Dictionary protected with a lock, it is more efficient under heavy usage because of its granular locking implementation. Instead of all threads competing for a single lock, the ConcurrentDictionary maintains multiple locks internally, minimizing this way the contention, and limiting the possibility of becoming a bottleneck.

Despite these nice characteristics, the number of scenarios where using a ConcurrentDictionary is the best option is actually quite small. There are two reasons for that:

  1. The thread-safety guaranties offered by the ConcurrentDictionary are limited to the protection of its internal state. That's it. If you want to do anything slightly non-trivial, like for example updating the dictionary and another variable as an atomic operation, you are out of luck. This is not a supported scenario for a ConcurrentDictionary. Even protecting the elements it contains (in case they are mutable objects) is not supported. If you try to update one of its values using the AddOrUpdate method, the dictionary will be protected but the value will not. The Update in this context means replace the existing value with another one, not modify the existing value.

  2. Whenever you find tempting to use a ConcurrentDictionary, there are usually better alternatives available. Alternatives that do not involve shared state, which is what a ConcurrentDictionary essentially is. No matter how efficient is its locking scheme, it will have a hard time beating an architecture where there is no shared state at all, and each thread does its own thing without interfering with the other threads. Commonly used libraries that follow this principle are the PLINQ and the TPL Dataflow library. Below is a PLINQ example:

Dictionary<string, Product> dictionary = productIDs
    .AsParallel()
    .Select(id => GetProduct(id))
    .ToDictionary(product => product.Barcode);

Instead of creating a dictionary beforehand, and then having multiple threads filling it concurrently with values, you can trust PLINQ to produce a dictionary utilizing more efficient strategies, involving partitioning of the initial workload, and assigning each partition to a different worker thread. A single thread will eventually aggregate the partial results, and fill the dictionary.

Theodor Zoulias
  • 34,835
  • 7
  • 69
  • 104
4

The accepted answer above is correct. However, it is worth mentioning explicitly if a dictionary is not being modified i.e. it is only ever read from, regardless of number of threads, then Dictionary<TKey,TValue> is preferred because no synchronization is required.

e.g. caching config in a Dictionary<TKey,TValue>, that is populated only once at startup and used throughout the application for the life of the application.

When to use a thread-safe collection : ConcurrentDictionary vs. Dictionary

If you are only reading key or values, the Dictionary<TKey,TValue> is faster because no synchronization is required if the dictionary is not being modified by any threads.

  • This is a very useful answer!, how about if a dictionary is being read from 100,000 times a min, but updated every 5 mins (using a lock) is a normal dictionary still ok in this instance? or do I need to lock on each read? – Quade May 20 '22 at 09:51
  • @Quade unfortunatey yes. See [here](https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.dictionary-2?redirectedfrom=MSDN&view=net-7.0#thread-safety). If the dictionary is modified while being iterated over then it will become unstable. In such cases use a lock or consider using [ConcurrentDictionary](https://learn.microsoft.com/en-us/dotnet/api/system.collections.concurrent.concurrentdictionary-2?view=net-7.0). – Grant Colley Dec 23 '22 at 07:56
  • thanks @GrantC. In terms of performance, I assume a dictionary is lots faster, obviously locking to update is not ideal, as long as it can be done very quickly – Quade Dec 23 '22 at 12:23
  • @Quade just a thought on your problem updating a dictionary every 5 mins. In your scenario would it be possible to use two dictionaries, one for reading while the other is being updated? When the update is complete, take out a lock while you switch them i.e. the updated dictionary becomes the one for reading, while the other waits 5 mins before being updated then swicthed back. This way the only locking required is during the switch. – Grant Colley Jan 21 '23 at 22:16
  • great idea, seems to be much quicker – Quade Feb 17 '23 at 08:59