Когда 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 также будут работать в вашей ситуации...