寻找有关利用 AsParallel()
或 Parallel.ForEach()
来加快速度的小建议。
请参阅下面我得到的方法(针对此示例进行了简化/混合)。
它采用类似“美国、法国、亚太地区”的列表,其中“亚太地区”是其他 50 个“美国、法国、日本、意大利、英国”等国家/地区的别名。该方法应采用“美国、法国、亚太地区”,并将其转换为“美国”、“法国”以及“亚太地区”中的所有国家/地区的列表。
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();
}
将其并行化是否像将其更改为以下内容一样简单?使用 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();
}
最佳答案
几点。
只写 countriesAndAliases.AsParallel()
没用。 AsParallel()
使并行执行后出现的 Linq 查询的一部分。部分是空的,所以根本没有用。
通常你应该更换foreach
与 Parallel.ForEach()
.但要注意非线程安全的代码!你拥有了它。你不能把它包装成 foreach
因为List<T>.Add
本身不是线程安全的。
所以你应该这样做(抱歉,我没有测试,但它可以编译):
return countriesAndAliases
.AsParallel()
.SelectMany(s =>
IsCountryNotAlias(s)
? Enumerable.Repeat(s,1)
: AliasCountryLists[s]
).Distinct();
编辑:
你必须确定另外两件事:
-
IsCountryNotAlias
必须是线程安全的。如果是pure function就更好了. - 没有人会修改
AliasCountryLists
同时,因为字典不是线程安全的。或者使用 ConcurrentDictionary可以肯定。
对您有帮助的有用链接:
Parallel Programming in .NET 4 Coding Guidelines
When Should I Use Parallel.ForEach? When Should I Use PLINQ?
PS:如您所见,新的并行功能并不像看起来(和感觉)那么明显。
关于c# - 使用 'AsParallel()'/'Parallel.ForEach()' 指针?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3780870/