Метод GetOrAdd
не так уж хорош для этой цели. Так как он не гарантирует, что фабрика запускается только один раз, единственная цель, которую он имеет, - это небольшая оптимизация (незначительная, поскольку добавления в любом случае редки) в том, что ей не нужно хешировать и дважды находить правильный сегмент (что может произойти дважды, если вы получаете и устанавливаете с двумя отдельными вызовами).
Я бы посоветовал сначала проверить кеш, если вы не нашли значение в кеше, а затем ввести некую форму критической секции (блокировка, семафор и т. Д.), Перепроверить кеш, если он все еще отсутствует, то получить значение и вставить в кеш.
Это гарантирует, что ваш бэк-магазин будет поражен только один раз; даже если несколько запросов одновременно пропускают кэш, только первый из них фактически извлечет значение, остальные запросы будут ожидать семафор, а затем возвращаться рано, поскольку они повторно проверяют кэш в критической секции.
Код Psuedo (используется SemaphoreSlim со счетчиком 1, поскольку вы можете ожидать его асинхронно):
async Task<TResult> GetAsync(TKey key)
{
// Try to fetch from catch
if (cache.TryGetValue(key, out var result)) return result;
// Get some resource lock here, for example use SemaphoreSlim
// which has async wait function:
await semaphore.WaitAsync();
try
{
// Try to fetch from cache again now that we have entered
// the critical section
if (cache.TryGetValue(key, out result)) return result;
// Fetch data from source (using your HttpClient or whatever),
// update your cache and return.
return cache[key] = await FetchFromSourceAsync(...);
}
finally
{
semaphore.Release();
}
}