Parallel.ForEach с добавлением в список - PullRequest
65 голосов
/ 04 ноября 2011

Я пытаюсь запустить несколько функций, которые подключаются к удаленному сайту (по сети) и возвращают общий список. Но я хочу запустить их одновременно.

Например:

public static List<SearchResult> Search(string title)
{
    //Initialize a new temp list to hold all search results
    List<SearchResult> results = new List<SearchResult>();

    //Loop all providers simultaneously
    Parallel.ForEach(Providers, currentProvider =>
    {
        List<SearchResult> tmpResults = currentProvider.SearchTitle((title));

        //Add results from current provider
        results.AddRange(tmpResults);
    });

    //Return all combined results
    return results;
}

На мой взгляд, несколько вставок в «результаты» могут происходить одновременно ... Что может привести к сбою моего приложения.

Как мне этого избежать?

Ответы [ 5 ]

132 голосов
/ 04 ноября 2011

Вы можете использовать одновременную коллекцию .

Пространство имен System.Collections.Concurrent предоставляет несколько потоковобезопасных классов коллекции, которые должны использоваться вместо соответствующих типов в пространствах имен System.Collections и System.Collections.Generic, когда несколько потоков одновременно получают доступ к коллекции.

Вы можете, например, использовать ConcurrentBag, поскольку у вас нет гарантии, в каком порядке будут добавлены предметы.

Представляет потокобезопасный неупорядоченный набор объектов.

47 голосов
/ 04 ноября 2011
//In the class scope:
Object lockMe = new Object();    

//In the function
lock (lockMe)
{    
     results.AddRange(tmpResults);
}

По сути, блокировка означает, что только один поток может иметь доступ к этому критическому разделу одновременно.

22 голосов
/ 04 ноября 2011

Параллельные коллекции являются новыми для .Net 4;они предназначены для работы с новой параллельной функциональностью.

См. Параллельные коллекции в .NET Framework 4 :

До .NET 4 вам приходилосьпредоставьте свои собственные механизмы синхронизации, если несколько потоков могут обращаться к одной общей коллекции.Вы должны были заблокировать коллекцию ...

... [новые] классы и интерфейсы в System.Collections.Concurrent [добавленные в .NET 4] обеспечивают согласованную реализацию для [...] несколькихпроблемы многопоточного программирования, связанные с общими данными между потоками.

21 голосов
/ 01 декабря 2015

Для тех, кто предпочитает код:

public static ConcurrentBag<SearchResult> Search(string title)
{
    var results = new ConcurrentBag<SearchResult>();
    Parallel.ForEach(Providers, currentProvider =>
    {
        results.Add(currentProvider.SearchTitle((title)));
    });

    return results;
}
12 голосов
/ 17 ноября 2014

Это можно выразить кратко, используя PLINQ's AsParallel и SelectMany:

public static List<SearchResult> Search(string title)
{
    return Providers.AsParallel()
                    .SelectMany(p => p.SearchTitle(title))
                    .ToList();
}
...