Пытаюсь понять разницу между коллекциями ConcurrentBag<T> и List<T> по этой статье.
Мне почему-то казалось, что если я буду использовать List<T> и в тот момент, когда один поток будет туда что-то записывает и попытается тоже самое сделать другой поток, то выскочит exception, но нет, все работает.
Есть сценарий мультипоточной обработки, где в конце своей работы все потоки должны записывать свой результат в одну коллекцию:
class Program
{
static void Main(string[] args)
{
var results = new List<string>();
//var results = new ConcurrentBag<string>();
// STEP 1: Get results.
Parallel.For(1, 50000, idx =>
{
// Some process.
//...
results.Add("something");
});
// STEP 2: Process results.
foreach (var result in results)
{
//...
}
}
}
Какое преимущество я получаю в случаи использования ConcurrentBag<T> вместо List<T> в моем случаи?
И еще такой маленький подвопрос: results, его правильно называть разделяемым ресурсом?
Мне почему-то казалось, что если я буду использовать List и в тот момент, когда один поток будет туда что-то записывает и попытается тоже самое сделать другой поток, то выскочит exception
Проблема может возникнуть, а может и не возникнуть. Это и называется потоконебезопасная коллекция - когда проблема потенциально может быть. Сегодня работает, завтра упадет - так как нет гарантии, что при параллельной работе 2 потока не попытаются писать одновременно в список.
То, что список у вас внутри Parallel.For ещё не гарантирует параллельного доступа. Параллельный доступ - это когда в одну и ту же единицу времени 2 или более потока пытаются работать со списком. В вашем случае при первом, втором, третем запусках такого может и не случиться, но на 99 запуске код упадет.
мультипоточной обработки
Многопоточной
Какое преимущество я получаю в случаи использования ConcurrentBag вместо List
В случае выбора ConcurrentBag<T> вы получаете гарантию, что ваш код не упадет в многопоточной работе. При работе с List<T> никаких гарантий нет, нет даже гарантий от потери данных, не то, чтобы от исключений. Повторю - даже один и тот же многопоточный код может в 99 случаях сработать и в 1 случае упасть при работе с потоконебезопасными коллекциями.
results, его правильно называть разделяемым ресурсом?
Поскольку потоки его разделяют, то да
В конкретно вашем коде лично я не вижу смысла в разделении ресурса, гораздо проще написать так:
var results = Enumerable
.Range(1, 50000)
.AsParallel()
.Select(x=> /*....*/)
.ToList();
foreach (var result in results)
{
//...
}
Мне почему-то казалось, что если я буду использовать List и в тот момент, когда один поток будет туда что-то записывает и попытается тоже самое сделать другой поток, то выскочит exception, но нет, все работает.
List<T> не является потокобезопасным. Это означает, что он вообще не предпринимает никаких действий для защиты данных при доступе из разных потоков. Ни блокировок, ни даже проверок на одновременный доступ.
Исключения вы не получите, но и гарантии целостности данных - тоже. Используйте ConcurrentBag<T>
Апостиль в Лос-Анджелесе без лишних нервов и бумажной волокиты
Основные этапы разработки сайта для стоматологической клиники
Продвижение своими сайтами как стратегия роста и независимости