2011-11-03 85 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; 
}