D任务池: 等待所有任务完成

4
这与我之前的问题有关:D concurrent writing to buffer 假设你有一段代码,由两个连续的代码块A和B组成,其中B依赖于A。这在编程中非常常见。A和B都包含一个循环,其中每次迭代都可以并行运行:
double[] array = [ ... ]; // has N elements

// A
for (int i = 0; i < N; i++)
{
    job1(array[i]); // new task
}

// wait for all job1's to be done

// B
for (int i = 0; i < N; i++)
{
    job2(array[i]); // new task
}

只有在 A 完成后才能执行 B。我该如何等待 A 的所有任务完成后再执行 B?

1个回答

6
我假设您正在使用std.parallelism?我编写了std.parallelism,所以我可以让您了解一项设计决策。实际上,在std.parallelism的某些beta版本中有一个join函数。它等待所有任务完成,然后关闭任务池。但我删除了它,因为我意识到它是无用的。
原因是,如果您手动创建一组O(N)任务对象来迭代某个范围,则正在错误使用库。您应该改用并行foreach循环,该循环在将控制返回给调用线程之前自动加入。您的示例将变为:
foreach(ref elem; parallel(array)) {
    job1(elem); 
}

foreach(ref elem; parallel(array)) {
    job2(elem);
}

在这种情况下,job1job2 不应该启动新的任务,因为并行 foreach 循环已经使用了足够的任务来充分利用所有 CPU 核心。

我理解你的观点。但是如果我们想要遍历不太直接的东西,该怎么办呢?如果您想要遍历奇数索引,该怎么办?我需要构建一个新数组,以便可以使用foreach吗?有scopedTask几乎可以满足我的需求,但它仅限于迭代,而不是整个循环... - Taco de Wolff
4
如果你想迭代奇数索引,可以使用std.range.stride或者foreach(i; parallel(std.range.iota(1, array.length, 2))。std.parallelism的设计是基于一种假设,即std.algorithm和std.range中的高阶范围会提供这种灵活性,而不是在std.parallelism的设计中明确计划它。 - dsimcha
1
确实,由于范围创建的许多便利设施,这是一个漂亮的设计。我的四核2D FFT算法速度提高了约200%:),谢谢。顺便问一下,iota是否真的与希腊字母iota有关? ^^ - Taco de Wolff
@Daevius 一点也不。这个名字来自于C++的iota函数,因为它基本上做了同样的事情。然而,这个名称实际上与它实际执行的操作完全没有关系。我不知道为什么会选择这个名称用于C++。许多人不喜欢这个名字,因为它真的没有什么意义,但是它和C++保持一致,并且很容易记住。 - Jonathan M Davis

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接