GetOrAdd
не гарантирует, что делегат будет вызываться только один раз, когда он вызывается из нескольких потоков одновременно с одним и тем же значением:
Если вы звоните TValue resultingValue ; если ( TryGetValue ( ключ , из resultingValue )) { вернуться resultingValue ; } TryAddInternal ( ключ , valueFactory ( ключ ), ложно , правда , из resultingValue ); return resultValue ; одновременно на разных потоках addValueFactory может вызываться несколько раз, но его пара ключ / значение не может быть добавлена ??в словарь для каждого вызова.
Это можно увидеть и в реализации :
GetOrAdd()
Итак, чтобы справиться с такой же хорошей работой , вы можете сделать что-то вроде (проверка ввода опущена):public static async Task<TValue> GetOrAddAsync<TKey, TValue>( this ConcurrentDictionary<TKey, TValue> dictionary, TKey key, Func<TKey, Task<TValue>> valueFactory) { TValue resultingValue; if (dictionary.TryGetValue(key, out resultingValue)) { return resultingValue; } return dictionary.GetOrAdd(key, await valueFactory(key)); }
GetOrAdd
Если требование не вызывать делегата дважды в то же время, это просто оптимизация производительности, этого должно быть достаточно.
Если это необходимо для правильности вашего кода, то даже GetOrAdd
этого недостаточно, и вам потребуется использовать дополнительную синхронизацию.