Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

312
Visualizações
Is ConcurrentDictionary.GetOrAdd() guaranteed to invoke valueFactoryMethod only once per key?

Problem: I need to implement object cache. The cache need to be thread-safe and need to populate values on demand(lazy loading). The values are retrieved via web service by Key(slow operation). So I've decided to use ConcurrentDictionary and its GetOrAdd() method that has a value factory method supposing that the operation is atomic and synchronized. Unfortunately I found the following statement in the MSDN article: How to: Add and Remove Items from a ConcurrentDictionary:

Also, although all methods of ConcurrentDictionary are thread-safe, not all methods are atomic, specifically GetOrAdd and AddOrUpdate. The user delegate that is passed to these methods is invoked outside of the dictionary's internal lock.

Well that's unfortunate but still doesn't answer my answer completely.

Question: Is value factory invoked only once per key? In my specific case: Is it possible that multiple threads that are looking for the same key spawning multiple request to the web service for the same value?

over 4 years ago · Santiago Trujillo
3 Respostas
Responde à pergunta

0

As others have already pointed out, valueFactory may be invoked more than once. There is a common solution that mitigates this issue - have your valueFactory return a Lazy<T> instance. Although it's possible that multiple lazy instances will be created, the actual T value will only be created when you access Lazy<T>.Value property.

Specifically:

// Lazy instance may be created multiple times, but only one will actually be used.
// GetObjectFromRemoteServer will not be called here.
var lazyObject = dict.GetOrAdd("key", key => new Lazy<MyObject>(() => GetObjectFromRemoteServer()));

// Only here GetObjectFromRemoteServer() will be called.
// The next calls will not go to the server
var myObject = lazyObject.Value;

This method is further explained in Reed Copsey's blog post

over 4 years ago · Santiago Trujillo Relatório

0

Is value factory invoked only once per key?

No, it isn't. The docs say:

If you call GetOrAdd simultaneously on different threads, valueFactory may be invoked multiple times, but its key/value pair might not be added to the dictionary for every call.

over 4 years ago · Santiago Trujillo Relatório

0

Let's take a look at the source code of GetOrAdd:

public TValue GetOrAdd(TKey key, Func<TKey, TValue> valueFactory)
{
    if (key == null) throw new ArgumentNullException("key");
    if (valueFactory == null) throw new ArgumentNullException("valueFactory");

    TValue resultingValue;
    if (TryGetValue(key, out resultingValue))
    {
        return resultingValue;
    }
    TryAddInternal(key, valueFactory(key), false, true, out resultingValue);
    return resultingValue;
}

Unfortunately, in this case, it's clear nothing guarantees that valueFactory won't be called more than once, if two GetOrAdd invocations happen to run in parallel.

over 4 years ago · Santiago Trujillo Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda