C# Parallel.ForEach与添加到列表

C# Parallel.ForEach与添加到列表,c#,list,locking,parallel-processing,C#,List,Locking,Parallel Processing,我正在尝试运行多个函数,这些函数连接到远程站点(通过网络)并返回一个通用列表。但我想同时运行它们 public static ConcurrentBag<SearchResult> Search(string title) { var results = new ConcurrentBag<SearchResult>(); Parallel.ForEach(Providers, currentProvider => { res

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

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

    return results;
}
例如:

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

    return results;
}
公共静态列表搜索(字符串标题)
{
//初始化新临时列表以保存所有搜索结果
列表结果=新列表();
//同时循环所有提供程序
Parallel.ForEach(提供程序,currentProvider=>
{
List tmpResults=currentProvider.SearchTitle((title));
//从当前提供程序添加结果
结果:AddRange(tmpResults);
});
//返回所有组合结果
返回结果;
}
在我看来,“结果”的多次插入可能同时发生。。。这可能会使我的应用程序崩溃

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

    return results;
}
我怎样才能避免这种情况

//In the class scope:
Object lockMe = new Object();    

//In the function
lock (lockMe)
{    
     results.AddRange(tmpResults);
}
public static ConcurrentBag<SearchResult> Search(string title)
{
    var results = new ConcurrentBag<SearchResult>();
    Parallel.ForEach(Providers, currentProvider =>
    {
        results.Add(currentProvider.SearchTitle((title)));
    });

    return results;
}

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

对于.Net 4来说,并发集合是新的;它们被设计用于使用新的并行功能

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

    return results;
}
见:

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

    return results;
}
在.NET4之前,如果多个线程可能正在访问单个共享集合,则必须提供自己的同步机制。你必须锁定收藏

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

    return results;
}
。。。System.Collections.Concurrent[添加到.NET 4]中的[新]类和接口为涉及跨线程共享数据的[…]多线程编程问题提供了一致的实现

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

    return results;
}
你可以用一个

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

    return results;
}
System.Collections.Concurrent
命名空间提供了多个线程安全的集合类,当多个线程同时访问集合时,这些类应替代
System.Collections
System.Collections.Generic
命名空间中的相应类型

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

    return results;
}
例如,您可以使用,因为您无法保证添加项目的顺序

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

    return results;
}
表示线程安全的无序对象集合

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

    return results;
}

这可以用PLINQ的
aspallel
SelectMany
简洁地表达出来:

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

    return results;
}
公共静态列表搜索(字符串标题)
{
返回提供程序
.SelectMany(p=>p.SearchTitle(title))
.ToList();
}

对于喜欢代码的人:

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

    return results;
}
公共静态ConcurrentBag搜索(字符串标题)
{
var结果=新的ConcurrentBag();
Parallel.ForEach(提供程序,currentProvider=>
{
添加(currentProvider.SearchTitle((title));
});
返回结果;
}

您使用的是哪个.NET版本?它必须至少是.NET 4;这里引入了并行。但是如果在添加这些结果时,来自另一个提供商的结果试图添加到中,会发生什么?他们会失败还是等到可能?当有锁时,线程会等到它能得到锁。所以基本上就像说:等到!results.isLocked,当其空闲时将其锁定并写入?一个次要问题:
这对于lock对象来说不是最安全的选择。最好使用一个特殊的私有对象:
lock(resultsLock)
locks
可以降低总体执行时间。。并发集合似乎更好地避免这种情况是的,这是实际的答案。通过并发集合,您(通常)会获得更好的性能。linq selectMany很棒,遗憾的是,linq的速度比普通foreach慢(不要进行微优化。OP意味着
SearchTitle
连接到远程站点。其延迟将比LINQ和foreach之间的差异慢几个数量级。必须使用循环:
foreach(currentProvider.SearchTitle((title))中的var项)结果。添加(项);