c# - C# 并行 foreach 没有提供预期的加速
问题描述
我试图找出为什么并行 foreach 不能在具有 32 个物理内核和 64 个逻辑内核的机器上通过简单的测试计算给出预期的加速。
...
var parameters = new List<string>();
for (int i = 1; i <= 9; i++) {
parameters.Add(i.ToString());
if (Scenario.UsesParallelForEach)
{
Parallel.ForEach(parameters, parameter => {
FireOnParameterComputed(this, parameter, Thread.CurrentThread.ManagedThreadId, "started");
var lc = new LongComputation();
lc.Compute();
FireOnParameterComputed(this, parameter, Thread.CurrentThread.ManagedThreadId, "stopped");
});
}
else
{
foreach (var parameter in parameters)
{
FireOnParameterComputed(this, parameter, Thread.CurrentThread.ManagedThreadId, "started");
var lc = new LongComputation();
lc.Compute();
FireOnParameterComputed(this, parameter, Thread.CurrentThread.ManagedThreadId, "stopped");
}
}
}
...
class LongComputation
{
public void Compute()
{
var s = "";
for (int i = 0; i <= 40000; i++)
{
s = s + i.ToString() + "\n";
}
}
}
Compute 功能大约需要 5 秒才能完成。我的假设是,对于并行 foreach 循环,每次额外的迭代都会创建一个在其中一个内核上运行的并行线程,并且只需要计算一次 Compute 函数所需的时间。因此,如果我运行循环两次,然后使用顺序 foreach,则需要 10 秒,而并行 foreach 只需 5 秒(假设有 2 个内核可用)。加速比为 2。如果我运行循环 3 次,那么使用顺序 foreach 将需要 15 秒,但再次使用并行 foreach 只需 5 秒。加速比是 3,然后是 4、5、6、7、8 和 9。但是,我观察到的加速比恒定为 1.3。
顺序与并行 foreach。X 轴:计算的顺序/并行执行次数。Y轴:以秒为单位的时间
FireOnParameterComputed 中触发的事件旨在用于 GUI 进度条以显示进度。在进度条中可以清楚地看到,对于每次迭代,都会创建一个新线程。
我的问题是,为什么我没有看到预期的加速或至少接近预期的加速?
解决方案
任务不是线程。
有时启动任务会导致创建线程,但并非总是如此。创建和管理线程会消耗时间和系统资源。当一项任务只需要很短的时间时,即使它违反直觉,单线程模型通常也会更快。
CLR 知道这一点,并尝试根据许多因素(包括您传递给它的任何提示)对如何执行任务做出最佳判断。
对于 Parallel.ForEach,如果您确定要生成多个线程,请尝试传入 ParallelOptions。
Parallel.ForEach(parameters, new ParallelOptions { MaxDegreeOfParallelism = 100 }, parameter => {});
推荐阅读
- typo3 - 如何设置 tt_address 4.x 以使用 TYPO3 9 LTS 中的 insert_records
- javascript - req.checkBody 不是函数,express-validator 中间件不起作用
- php - array_push 与多维数组
- css - 如何使波浪下划线延伸覆盖Chrome中的所有字符
- numpy - Distributions.jl 不接受我的(非正定)协方差函数(而 numpy 接受)
- django - 当form.save()不返回对象时,如何在保存模型表单对象后从django FileField中获取多个文件
- javascript - 带回调的单元测试异步函数
- python-3.x - 当列表中的值大于 0 时,如何将一个数字添加到列表中的另一个数字?
- r - Mutate dataframe and carry out partial string match
- r - remove layers from ggplot chart with particular layers automatically