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.Collections
和System.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的AsParallel
和SelectMany
简洁地expression:
public static List<SearchResult> Search(string title) { return Providers.AsParallel() .SelectMany(p => p.SearchTitle(title)) .ToList(); }