问题
I'm trying to run multiple functions that connect to a remote site (by network) and return a generic list. But I want to run them simultaneously.
For example:
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;
}
As I see it, multiple insertions to 'results' may happend at the same time... Which may crash my application.
How can I avoid this?
回答1:
//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.
回答2:
You can use a concurrent collection.
The
System.Collections.Concurrentnamespace provides several thread-safe collection classes that should be used in place of the corresponding types in theSystem.CollectionsandSystem.Collections.Genericnamespaces 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.
回答3:
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.
回答4:
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;
}
回答5:
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();
}
来源:https://stackoverflow.com/questions/8001748/parallel-foreach-with-adding-to-list