Я использую Parallel.Foreach для заполнения внешнего ConcurrentBag. Я также попытался использовать общий список, и все работает нормально.
Мне повезло, или я пропустил специальный объем ConcurrentBag?
Я использую Parallel.Foreach для заполнения внешнего ConcurrentBag. Я также попытался использовать общий список, и все работает нормально.
Мне повезло, или я пропустил специальный объем ConcurrentBag?
Вам повезло; Parallel.ForEach
для заполнения списка не является потокобезопасным, вы в конечном итоге столкнетесь с проблемами.
Согласно MSDN, List<T>
не является безопасным по потоку:
Любые члены экземпляра не гарантируют безопасность потоков.
A Список <T> может поддерживать несколько считывателей одновременно, пока коллекция не модифицировано. Перечисление через коллекцию по сути, не является потокобезопасной процедурой. В редком случае, когда перечисление связано с одним или несколькими обращениями на запись, единственным способом обеспечить безопасность потока, чтобы заблокировать сбор в течение всего перечисление. Чтобы обеспечить доступ к коллекции несколькими темы для чтения и письма, вы должны реализовать свои собственные синхронизации.
ConcurrentBag - это то, что вы должны использовать для этого, который является потокобезопасным для нескольких читателей и писателей.
Если вы используете Parallel.ForEach
для заполнения List<T>
, и все работает отлично, вам просто повезет. Метод ForEach
может и будет запускать ваш код на нескольких потоках, поэтому любая связь вне ForEach
должна быть с объектами, которые могут обрабатывать параллельные обновления. List<T>
может не ConcurrentBag<T>
can.
ConcurrentBag - правильный ответ, только в .NET 4.0 он очень медленный. Это было исправлено в .NET 4.5. См. http://ayende.com/blog/156097/the-high-cost-of-concurrentbag-in-net-4-0
Оба ConcurrentStack и ConcurrentQueue также будут работать в вашей ситуации...