There are some common issues I see when people use ConcurrentDictionary:
- Dealing with the fact that GetOrAdd executes the creation callback more than once. This means if you create something expensive, it'll happen more than once. (this is documented) #dotnet
- Dealing with the fact that GetOrAdd executes the creation callback more than once. This means if you create something expensive, it'll happen more than once. (this is documented) #dotnet
- If you create a disposable object in your factory and it gets called multiple times, the created objects will never be disposed.
- Making sure asynchronous factories and are called once. (making all callers wait on the same value).
- Making sure asynchronous factories and are called once. (making all callers wait on the same value).
Here's a contrived example of the resource leak. The code runs a couple of concurrent operations and uses GetOrAdd to cache a FileStream. This will call File.OpenRead potentially multiple times which will result in opening a handle to the resource and not disposing it.
Even though we disposed the final handle, the ones that were created won't be disposed. This means the subsequent File.OpenWrite will fail (because this file was opened with shared read access only).
Here's another one of my favorites, cached values that need to run asynchronously to produce the result. These may also be expensive to run so it's typical to want to avoid running these multiple times. A large number of requests entering the cache might make things fall over.
Here's an example of caching the results of an outgoing HTTP request. Ideally this expensive operation would only happen once, but alas, the concurrent dictionary doesn't guarantee this. Now you're making lots of outbound requests when you thought you were doing one.