mpi*_*ium 4 .net c# multithreading .net-core
我正在尝试并行化任务,但没有获得良好的性能。我最多只能得到 50% 的 CPU 使用率。
下面是一个玩具示例,我构建了一个随机单词列表的列表,然后遍历每个单词并反转它的字符串。反转部分是我试图并行化的部分。
对我来说,这看起来像是一个 CPU 限制问题,所以我不太明白为什么 CPU 使用率如此低。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Papa
{
class Program
{
static void Main(string[] args)
{
// Build source
var random = new Random();
var alphabet = "abcdefghijklmnopqrstuvwxyz";
Console.WriteLine("Building data source");
var source = new List<string[]>();
foreach (var i in Enumerable.Range(0, 5000000))
{
var words = random.Next(3, 50);
var line = new List<string>();
for (var j = 0; j < words; ++j)
{
line.Add(
string.Concat(
Enumerable
.Range(0, random.Next(3, 9))
.Select(w => alphabet[random.Next(0, alphabet.Length - 1)])
)
);
}
source.Add(line.ToArray());
}
// Process source
Console.WriteLine("Processing source");
var processed = new List<string[]>();
Parallel.ForEach(
source,
() => new List<string[]>(),
(line, loop, local) =>
{
var processedLine = new List<string>();
for (var i = 0; i < line.Count(); ++i)
{
processedLine.Add(string.Concat(line[i].Reverse()));
}
local.Add(processedLine.ToArray());
return local;
},
partitionResult =>
{
lock (processed)
{
processed.AddRange(partitionResult);
}
});
}
}
}
Run Code Online (Sandbox Code Playgroud)
Parallel.ForEach将使用调度程序默认提供的尽可能多的线程(参考)。请注意,文档指出:
在分区器上执行 foreach(在 Visual Basic 中为 For Each)操作,其中迭代可以并行运行,并且可以配置循环选项。
因此,可能的情况是它似乎不适合默认选项。
运行代码后,我发现以下内容(当点击并行部分时):
正如您所看到的,它已经使用了 15Gb 内存,但它在所有内核上运行。我很确定您会遇到内存/GC 瓶颈而不是 CPU 瓶颈。
我运行了一些额外的性能分析。这是我发现的(String::Concat可以忽略,因为它是初始化的一部分):
第 45 行占用了大约 50% 的 CPU 时间。
我对代码进行了一些修改并进行了以下更改:
Parallel.ForEach(
source,
() => new List<string[]>(),
(line, loop, local) =>
{
var length = line.Length;
var processedLine = new string[length];
for (var i = 0; i < length; ++i)
{
processedLine[i] = line[i].Reverse() + "";
}
local.Add(processedLine);
return local;
},
partitionResult =>
{
lock (processed)
{
processed.AddRange(partitionResult);
}
});
Run Code Online (Sandbox Code Playgroud)
当数据大小加倍(10000000~32Gb 数据)时,这至少显示了 CPU 使用率的一个小峰值,但它在不到7 秒的时间内完成,所以我不太确定 TaskManager 是否真的正确地获得了峰值。尽管如此,这也不能解决问题,GC 也疯狂运行。
我的“最终”结论是,它是以下之一(或多个):
这限制了你。
在我看来,这是一个很好的例子,说明即使您可以使用x线程,并行化也不会产生x倍的性能。
| 归档时间: |
|
| 查看次数: |
1815 次 |
| 最近记录: |