使用添加到 list 的并行

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

例如:

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

在我看来,对“结果”的多次插入可能同时发生... ... 这可能会使我的应用程序崩溃。

我怎样才能避免这种情况呢?

107613 次浏览
//In the class scope:
Object lockMe = new Object();


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

Basically a lock means that only one thread can have access to that critical section at the same time.

The Concurrent Collections are new for .Net 4; they are designed to work with the new parallel functionality.

See Concurrent Collections in the .NET Framework 4:

Before .NET 4, you had to provide your own synchronization mechanisms if multiple threads might be accessing a single shared collection. You had to lock the collection ...

... the [new] classes and interfaces in System.Collections.Concurrent [added in .NET 4] provide a consistent implementation for [...] multi-threaded programming problems involving shared data across threads.

You can use a concurrent collection.

The System.Collections.Concurrent namespace provides several thread-safe collection classes that should be used in place of the corresponding types in the System.Collections and System.Collections.Generic namespaces whenever multiple threads are accessing the collection concurrently.

You could for example use ConcurrentBag since you have no guarantee which order the items will be added.

Represents a thread-safe, unordered collection of objects.

This could be expressed concisely using PLINQ's AsParallel and SelectMany:

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

For those who prefer code:

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


return results;
}