A little trick when working with ConcurrentDictionary

ConcurentDictionary has one specific feature: in some cases it may not behave exactly as you'd expect. Here is a small example. Let's say we need to do some small caching so that the results of an expensive calculation be taken from the cache if they are there, and be added to the cache in a transparent manner if someone made a mistake.

ConcurentDictionary has one specific feature: in some cases it may not behave exactly as you'd expect. Here is a small example. Let's say we need to do some small caching so that the results of an expensive calculation be taken from the cache if they are there, and be added to the cache in a transparent manner if someone made a mistake.

A simple implementation of a provider with a cache aside pattern would look like this:


In terms of multi-threading, this implementation is absolutely correct. Even if method RunOperationOrGetFromCache for the same operationId was invoked from two threads, each of them will get the same result. The problem, however, is that, although the result will be the same, we will have two operations running. The result of the first operation will be placed in the cache and the result of the second operation will be thrown away!

The reason lies in implementing the method AddOrGet of class ConcurrentDictionary. In fact, the use of AddOrGet is equivalent to the consistent use of methods like TryGetValue TryAdd in our own code (method AddOrGet is a little more complicated than a simple invocation of these two methods):


Now, it should be clear that if two threads are going to conflict and simultaneously try to get the results of the same operation, a long term operation will be run twice.

However, it's not all that bad. Since the competitive invocation of method AddOrGet will place only the first result in the collection, you can use the following trick:


Instead of only storing the result of a long operation, the cache will also store the "lazy shell" - Lazy . In this case, during simultaneous referring to the cache from multiple threads only a constructor of object Lazy <T>, , will be invoked several times and the operation itself will be run only once - when accessing the property Value!

Sergey Teplyakov
Expert in .Net, С++ and Application Architecture

Share the knowledge

loading map...
Luxoft Warsaw - Warsaw Spire, plac Europejski 1, 00-844 Warszawa
loading map...
Dimitrie Pompeiu nr 5-7 , building C, Et. 5, sect 2, Bucharest, 014459

Contact phone:

021 371 4858
loading map...
Luxoft Poland Wrocław - Silver Tower pl. Konstytucji 3-go Maja 3 50-048 Wrocław
loading map...
Aleja Generała Tadeusza Bora-Komorowskiego 25, Quattro Business Park Five, 31-476 Kraków, Poland

Contact phone:

+48 122110650
Success
Thank you.
Your request has been received.