ConcurrentDictionary.GetOrAdd под параллельной нагрузкой
Кэш справочника тарифов в памяти сервиса реализован так:
private readonly ConcurrentDictionary<int, Tariff> _cache = new();
public Tariff Get(int id) => _cache.GetOrAdd(id, key => LoadFromDb(key));
LoadFromDb — тяжёлый запрос к базе (около 400 мс). В пике на холодный кэш прилетает 50 одновременных запросов с одним и тем же id. Какое утверждение верно?
- GetOrAdd берёт блокировку на время выполнения фабрики, поэтому запрос к базе выполнится ровно один раз, а остальные потоки дождутся готового значения
- Возможна гонка, и в словаре для одного ключа окажется несколько разных значений
- Значение для ключа окажется ровно одно, но фабрика может выполниться параллельно несколько раз — лишние результаты отбрасываются
- ConcurrentDictionary не защищает от одновременного доступа при записи, поэтому весь метод нужно обернуть в lock
