Подтвердить что ты не робот

ConcurrentDictionary <TKey, TValue> vs Dictionary <TKey, TValue>

Как MSDN говорит

ConcurrentDictionary<TKey, TValue> Класс Представляет потокобезопасную коллекцию пар ключ-значение, к которым одновременно можно обращаться несколькими потоками.

Но, как я знаю, классы System.Collections.Concurrent предназначены для PLINQ.

У меня есть Dictionary<Key,Value>, который держит он-лайн клиентов на сервере, и я делаю его потокобезопасным, блокируя объект, когда у меня есть к нему доступ.

Могу ли я безопасно заменить Dictionary<TKey,TValue> на ConcurrentDictionary<TKey,TValue> в моем случае? увеличится ли производительность после замены?

Здесь в части 5 Джозеф Альбахари упомянул, что он предназначен для параллельного программирования

  • Совпадающие коллекции настраиваются для параллельного программирования. Обычные коллекции превосходят их во всех, но очень параллельных сценариях.
  • Нитебезопасная коллекция не гарантирует, что использующий ее код будет потокобезопасным.
  • Если вы перечисляете параллельную коллекцию, а другой поток ее модифицирует, исключение не генерируется. Вместо этого вы получаете смесь старого и нового контента.
  • Отсутствует параллельная версия списка.
  • Сопутствующие классы стека, очереди и пакета реализуются внутри со связанными списками. Это делает их менее эффективными с точки зрения памяти, чем неконкурентные классы Stack и Queue, но лучше для одновременного доступа, поскольку связанные списки способствуют реализации без блокировки или с низкой блокировкой. (Это связано с тем, что вставка node в связанный список требует обновления только нескольких ссылок, в то время как вставка элемента в структуру, подобную List, может потребовать перемещения тысяч существующих элементов.)
4b9b3361

Ответ 1

Не зная больше о том, что вы делаете в замке, тогда это невозможно сказать.

Например, если весь доступ к вашему словарю выглядит следующим образом:

lock(lockObject)
{
    foo = dict[key];
}

... // elsewhere

lock(lockObject)
{
    dict[key] = foo;
}

Тогда вы будете нормально его отключать (хотя вы, вероятно, не увидите никакой разницы в производительности, поэтому, если он не сломался, не исправить). Однако, если вы делаете что-либо в блоке блокировки, где вы взаимодействуете со словарем, тогда вам нужно будет убедиться, что словарь предоставляет единственную функцию, которая может выполнить то, что вы делаете в блоке блокировки, иначе вы В итоге вы получите код, функционально отличающийся от того, что у вас было раньше. Самое главное помнить, что словарь гарантирует, что одновременные вызовы словаря исполняются серийно; он не может обрабатывать случаи, когда в вашем коде есть одно действие, которое несколько раз взаимодействует со словарем. Такие случаи, когда не учитываются ConcurrentDictionary, требуют вашего собственного элемента управления concurrency.

К счастью, ConcurrentDictionary предоставляет некоторые вспомогательные функции для более общих многошаговых операций, таких как AddOrUpdate или GetOrAdd, но они не могут охватить все обстоятельства. Если вы обнаружите, что вам нужно работать, чтобы обучить вашу логику этим функциям, лучше справиться с вашим собственным concurrency.

Ответ 2

Это не так просто, как замена Dictionary на ConcurrentDictionary, вам нужно будет адаптировать ваш код, поскольку у этих классов есть новые методы, которые ведут себя по-другому, чтобы гарантировать безопасность потоков.

Например, вместо вызова Add или Remove у вас есть TryAdd и TryRemove. Важно, чтобы вы использовали эти методы, которые ведут себя атомарно, как если бы вы делали два вызова, в которых вторая зависит от результата первого, у вас все еще будут условия гонки и требуется lock.

Ответ 3

Вы можете заменить Dictionary<TKey, TValue> на ConcurrentDictionary<TKey, TValue>.

Эффект на производительность может быть не таким, каким вы хотите (если есть много блокировки/синхронизации, производительность может пострадать... но по крайней мере ваша коллекция не подвержена потоку).

Ответ 4

Пока я не уверен в проблемах с заменой, но если у вас есть где-то, где вам нужно получить доступ к нескольким элементам в словаре в том же "сеансе блокировки", вам нужно будет изменить свой код.

Это может обеспечить улучшенную производительность, если Microsoft предоставила отдельные блокировки для чтения и записи, поскольку операции чтения не должны блокировать другие операции чтения.

Ответ 5

Да, вы можете спокойно заменить, однако словарь, предназначенный для plinq, может содержать дополнительный код для добавления функциональных возможностей, которые вы не можете использовать. Но накладные расходы производительности будут незначительно очень маленькими.