2011-11-03 32 views
48

我試圖運行連接到遠程站點(通過網絡)的多個函數並返回一個通用列表。但我想同時運行它們。Parallel.ForEach添加到列表

例如:

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; 
} 

依我之見,多次插入到「結果」可以在同一時間...這可能會崩潰我的應用程序happend。

我該如何避免這種情況?

+0

哪個.NET版本您使用的? – sll

+3

它必須至少.Net 4;在那裏引入了並行。 – arootbeer

回答

36
//In the class scope: 
Object lockMe = new Object();  

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

基本上鎖意味着只有一個線程可以同時訪問該關鍵部分。

+0

但是,如果WHILE將這些結果添加到另一個提供商的結果中,會發生什麼情況?他們會失敗還是等待直到可能? – shaharmor

+3

當存在鎖定時,線程將等待,直到它可以獲得鎖定。 – Haedrian

+0

所以基本上就是這樣說: 等到直到!results.isLocked,並且它的時候自由鎖定它並寫入? – shaharmor

21

Concurrent Collections是.Net 4的新增功能;它們被設計爲與新的並行功能一起工作。

Concurrent Collections in the .NET Framework 4

.NET 4之前,您必須提供自己的同步機制,如果多個線程可能訪問一個共享的集合。您必須鎖定集合...

... System.Collections.Concurrent [在.NET 4中添加]中的[new]類和接口爲多線程編程提供了一致的實現涉及跨線程共享數據的問題。

94

您可以使用concurrent collection

System.Collections.Concurrent命名空間提供了應在的地方對應的類型在System.CollectionsSystem.Collections.Generic命名空間,只要多個線程同時訪問該集合使用幾個線程安全的集合類。

例如,您可以使用ConcurrentBag,因爲您不能保證將添加項目的順序。

表示一個線程安全的,無序的對象集合。

+3

這應該被標記爲答案! – Misiu

+0

是的,這是實際的答案。併發集合可以獲得更好的性能(通常)。 – lkg

+0

標記爲答案! – Serdar

10

這可以通過使用來表達簡潔PLINQ的AsParallelSelectMany

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

對於那些誰喜歡代碼:

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

    return results; 
}