Когда ConcurrentBag лучше, чем список? - PullRequest
12 голосов
/ 25 августа 2011

Я использую Parallel.Foreach для заполнения внешнего ConcurrentBag. Я пытался также использовать общий список, и все отлично работает.

Мне повезло или я пропустил специальную область применения ConcurrentBag?

Ответы [ 3 ]

18 голосов
/ 25 августа 2011

Вам повезло;Parallel.ForEach заполнение списка не является потокобезопасным, вы в конечном итоге столкнетесь с проблемами.

Согласно MSDN, List<T> не является поточно-безопасным:

Любые члены экземпляране гарантируется поточно-ориентированная.

Список может одновременно поддерживать несколько считывателей, если коллекция не изменена.Перечисление через коллекцию по сути не является потокобезопасной процедурой.В редком случае, когда перечисление конкурирует с одним или несколькими доступами на запись, единственный способ обеспечить безопасность потока - заблокировать коллекцию в течение всего перечисления.Чтобы разрешить доступ к коллекции из нескольких потоков для чтения и записи, вы должны реализовать собственную синхронизацию.

ConcurrentBag - это то, что вы должны использовать для этого, которая поточно-ориентирована для нескольких читателей и писателей..

5 голосов
/ 25 августа 2011

Если вы используете Parallel.ForEach для заполнения List<T> и все работает просто отлично, то вам просто повезло. Метод ForEach может и будет запускать ваш код в нескольких потоках, поэтому любая связь за пределами ForEach должна осуществляться с объектами, которые могут обрабатывать одновременные обновления. List<T> не может, но ConcurrentBag<T> может.

2 голосов
/ 20 июля 2012

ConcurrentBag - правильный ответ, только в .NET 4.0 он очень медленный. Это было исправлено в .NET 4.5. Смотри http://ayende.com/blog/156097/the-high-cost-of-concurrentbag-in-net-4-0

И ConcurrentStack, и ConcurrentQueue также будут работать в вашей ситуации ...

...