使用AsParallel()/ Parellel.ForEach()指南?

Sni*_*ave 43 .net c# parallel-processing multithreading

寻找有关利用AsParallel()Parallel.ForEach()加快这一点的一些建议.

请参阅下面的方法(本例中简化/标准化).

它需要一个像"US,FR,APAC"这样的列表,其中"APAC"是50个其他"US,FR,JP,IT,GB"等的别名.该方法应采用"US,FR,APAC",并将其转换为"US","FR"列表以及"APAC"中的所有国家/地区.

private IEnumerable<string> Countries (string[] countriesAndAliases)
{
    var countries = new List<string>();

    foreach (var countryOrAlias in countriesAndAliases)
    {
        if (IsCountryNotAlias(countryOrAlias))
        {
            countries.Add(countryOrAlias);
        }
        else 
        {
            foreach (var aliasCountry in AliasCountryLists[countryOrAlias]) 
            {
                countries.Add(aliasCountry);
            }
        }
    }

    return countries.Distinct();
}
Run Code Online (Sandbox Code Playgroud)

是否将其并行化为将其更改为以下内容?使用AsParallel()比这更细微吗?我应该使用Parallel.ForEach()而不是foreach?并行化foreach循环时我应该使用哪些经验法则?

private IEnumerable<string> Countries (string[] countriesAndAliases)
{
    var countries = new List<string>();

    foreach (var countryOrAlias in countriesAndAliases.AsParallel())
    {
        if (IsCountryNotAlias(countryOrAlias))
        {
            countries.Add(countryOrAlias);
        }
        else 
        {
            foreach (var aliasCountry in AliasCountryLists[countryOrAlias].AsParallel()) 
            {
                countries.Add(aliasCountry);
            }
        }
    }

    return countries.Distinct();
}
Run Code Online (Sandbox Code Playgroud)

And*_*rey 69

几点.

写作只是countriesAndAliases.AsParallel()没用.AsParallel()成为并行执行后的Linq查询的一部分.部分是空的,所以根本没用.

通常你应该repace foreachParallel.ForEach().但要注意不是线程安全的代码!你拥有了它.你不能把它包装成foreach因为它List<T>.Add本身不是线程安全的.

所以你应该这样做(对不起,我没有测试,但它编译):

        return countriesAndAliases
            .AsParallel()
            .SelectMany(s => 
                IsCountryNotAlias(s)
                    ? Enumerable.Repeat(s,1)
                    : AliasCountryLists[s]
                ).Distinct();
Run Code Online (Sandbox Code Playgroud)

编辑:

你必须确定另外两件事:

  1. IsCountryNotAlias必须是线程安全的.如果它是纯粹的功能会更好.
  2. 同时没有人会修改AliasCountryLists,因为字典不是线程安全的.或者使用ConcurrentDictionary来确定.

有用的链接,可以帮助您:

并行编程模式:使用.NET Framework理解和应用并行模式4

.NET 4编码指南中的并行编程

我什么时候应该使用Parallel.ForEach?我什么时候应该使用PLINQ?

PS:正如您所看到的那样,新的并行功能并不像它们看起来那样明显(和感觉).


Ree*_*sey 13

使用AsParallel()时,您需要确保您的身体是线程安全的.不幸的是,上面的代码不起作用. List<T>不是线程安全的,所以你的添加AsParallel()会导致竞争条件.

但是,如果您将集合切换为使用System.Collections.Concurrent中的集合,例如ConcurrentBag<T>,上述代码很可能会起作用.

  • "在上面的代码中添加`AsParallel()`"不会导致竞争条件,因为在c#的`foreach`中它将按顺序处理. (2认同)