Parallel.ForEach添加到列表

我试图运行连接到远程站点的多个函数(通过networking),并返回一个通用列表。 但我想同时运行它们。

例如:

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

正如我所看到的,多次插入“结果”可能会同时发生…这可能会导致我的应用程序崩溃。

我怎样才能避免这一点?

 //In the class scope: Object lockMe = new Object(); //In the function lock (lockMe) { results.AddRange(tmpResults); } 

基本上锁意味着只有一个线程可以同时访问该关键部分。

您可以使用并发收集 。

System.Collections.Concurrent命名空间提供了多个线程安全的集合类,只要多个线程同时访问集合,就应该使用它们来代替System.CollectionsSystem.Collections.Generic命名空间中的相应types。

例如,你可以使用ConcurrentBag因为你不能保证项目将被添加的顺序。

表示一个线程安全的,无序的对象集合。

Concurrent Collections是.Net 4的新function; 它们被devise成与新的并行function一起工作。

请参阅.NET Framework 4中的并发集合 :

在.NET 4之前,如果多个线程可能访问单个共享集合,则必须提供自己的同步机制。 你必须locking集合…

System.Collections.Concurrent [在.NET 4中添加]中的[new]类和接口为跨线程共享数据的multithreading编程问题提供了一致的实现。

对于那些喜欢代码的人:

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

这可以使用PLINQ的AsParallelSelectMany简洁地expression:

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