TGStat
TGStat
Введите текст для поиска
Расширенный поиск каналов
  • Язык сайта
    flag Russian flag English flag Uzbek
  • Вход на сайт
  • Каталог
    Каталог каналов и чатов Региональные подборки Тематические подборки Платные каналы Поиск каналов
    Добавить канал/чат
  • Рейтинги
    Рейтинг каналов Рейтинг чатов Рейтинг публикаций
    Рейтинги брендов и персон
  • Аналитика
  • Поиск по публикациям
  • Мониторинг Telegram
  • Продвижение
    Реклама через Яндекс Бизнес Реклама в каналах через TGStat Agency Реклама на сайте TGStat.ru
C# Ready | Unity

30 Sep, 11:12

Открыть в Telegram Поделиться Пожаловаться

Почему фабрика в ConcurrentDictionary.GetOrAdd может сработать несколько раз?

ConcurrentDictionary удобно использовать, когда несколько потоков обращаются к одному словарю. Кажется, что GetOrAdd одновременно проверяет ключ и ровно один раз создаёт значение:
var profile = cache.GetOrAdd(id, key => LoadProfile(key));

В словаре действительно останется одно значение для ключа. Но это не означает, что LoadProfile обязательно вызовется только один раз.

Фабрика выполняется вне внутренней блокировки словаря. Если два потока одновременно не нашли ключ, оба могут начать загрузку:
var first = cache.GetOrAdd(id, LoadProfile);
var second = cache.GetOrAdd(id, LoadProfile);

Словарь сохранит один результат и вернёт его обоим вызовам, а результат другой загрузки окажется лишним. Поэтому в фабрику не стоит помещать побочные эффекты, например списание денег или отправку письма.

Если повторное вычисление недорого и безопасно, обычный GetOrAdd подходит. Для дорогой инициализации можно хранить в словаре Lazy:
var pending = cache.GetOrAdd(id, key =>
new Lazy(() => LoadProfile(key)));
var profile = pending.Value;

Здесь у разных потоков тоже могут создаться несколько объектов Lazy, но в словаре останется один. У него загрузка при обращении к Value выполнится один раз при стандартном режиме Lazy.

Не забывайте и про ошибки. По умолчанию Lazy запоминает исключение фабрики, а значит последующие обращения к тому же Value снова получат эту ошибку:
cache.TryRemove(id, out _);

Удалять запись для повтора нужно с учётом конкуренции с другими запросами.

➡️ C# Ready | #совет

1.8k 0 5 2 11
Каталог
Каталог каналов и чатов Подборки каналов Поиск каналов Добавить канал/чат
Рейтинги
Рейтинг каналов Telegram Рейтинг чатов Telegram Рейтинг публикаций Рейтинги брендов и персон
API
API статистики API поиска публикаций API Callback
Наши каналы
@TGStat @TGStat_Chat @telepulse @TGStatAPI
Почитать
Академия TGStat Исследование Telegram 2019 Исследование Telegram 2021 Исследование Telegram 2023
Контакты
Справочный центр Поддержка Почта Вакансии
Всякая всячина
Пользовательское соглашение Политика конфиденциальности Публичная оферта
Наши боты
@TGStat_Bot @SearcheeBot @TGAlertsBot @tg_analytics_bot @TGStatChatBot