Разница между ConcurrentBag<T> и List<T>

215
05 сентября 2018, 10:10

Пытаюсь понять разницу между коллекциями 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, его правильно называть разделяемым ресурсом?

Answer 1

Мне почему-то казалось, что если я буду использовать 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)
{
    //...
}
Answer 2

Мне почему-то казалось, что если я буду использовать List и в тот момент, когда один поток будет туда что-то записывает и попытается тоже самое сделать другой поток, то выскочит exception, но нет, все работает.

List<T> не является потокобезопасным. Это означает, что он вообще не предпринимает никаких действий для защиты данных при доступе из разных потоков. Ни блокировок, ни даже проверок на одновременный доступ.

Исключения вы не получите, но и гарантии целостности данных - тоже. Используйте ConcurrentBag<T>

READ ALSO
Обновление данных в ListView (C#/WPF)

Обновление данных в ListView (C#/WPF)

Есть ListView в который записывается данные, дело в том что нету возможности записать все сразу, по этому необходимо изменять/обновлять данные...

184
как при наведении курсора на кнопку сделать появления справки Windows forms

как при наведении курсора на кнопку сделать появления справки Windows forms

Будет кнопка, и если удержать на этой кнопке мышку секунду где-то 05 будет появляться окно с текстом

174
Реализация протокола WebSocket на C#

Реализация протокола WebSocket на C#

На GitHub есть репозиторий с реализацией декодирования фреймов протокола WebSocketПроблема в том, что если в один момент времени отправляется много...

208
laravel авторизация роли и прав

laravel авторизация роли и прав

я составляю cms на laravel c возможность расширяться через плагиныВозник вопрос, у меня есть пользователи и каждому можно задавать роли админ...

192