ConcurrentDictionaryпротив словаря - PullRequest
27 голосов
/ 14 марта 2011

Как MSDN говорит

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

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

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

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

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

  • Параллельные коллекции настроены для параллельного программирования.Обычные коллекции превосходят их во всех сценариях, кроме сильно параллельных.
  • Потокобезопасная коллекция не гарантирует, что код, использующий ее, будет поточно-ориентированным.
  • Если вы перечислите по параллельномуВ то время как другой поток изменяет его, исключение не выдается.Вместо этого вы получаете смесь старого и нового содержимого.
  • Одновременной версии List не существует.
  • Параллельные классы stack, queue и bag реализованы внутри с помощью связанных списков.Это делает их менее эффективными в отношении памяти, чем классы непоследовательных стеков и очередей, но лучше для одновременного доступа, поскольку связанные списки способствуют реализации без блокировок или с низким блокированием.(Это связано с тем, что для вставки узла в связанный список требуется обновить только пару ссылок, а для вставки элемента в структуру, подобную списку, может потребоваться перемещение тысяч существующих элементов.)

Ответы [ 5 ]

16 голосов
/ 14 марта 2011

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

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

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

... // elsewhere

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

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

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

3 голосов
/ 14 марта 2011

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

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

1 голос
/ 14 марта 2011

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

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

1 голос
/ 14 марта 2011

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

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

0 голосов
/ 14 марта 2011

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

...