Когда ConcurrentBag лучше, чем список?

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

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

3 ответа

Решение

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

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

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

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

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

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

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

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

Другие вопросы по тегам