使用 cilk 计算 Fibonacci 的正确方法是什么?

What is the right way to compute Fibonacci using cilk?

在学习cilk的过程中,我举了两个相反的例子:

  1. From intel

  2. from wiki (or other examples in the net):

相反的是这两行:

x = spawn fib (n-1);
y = spawn fib (n-2);

第一个网站说:

You do not need to add a cilk_spawn attribute to the second recursive call to fib() because that will create an empty continuation

  1. 我不明白为什么?
  2. 正确的方法是什么? (使用 2 个 spawn 命令还是只使用一个?)

来自英特尔文档 "int x = cilk_spawn fib(n-1);" 的代码在另一个威胁中请求 运行 它的许可,而 "int y = fib(n-2);" 的下一行将是 运行 在同一威胁中作为主程序。 wiki 代码还要求计算 fib(n-2) 的新威胁,以便如果有超过三个处理器 运行 主程序 (fib(n))、fib (n-1) 和 fib (n-2) 全部针对不同的威胁。

如果只有两个处理器,两个代码将执行相同的操作。以下内容来自维基页面:

...处理器没有义务在别处分配衍生过程; 如果机器只有两个处理器当执行 fib(2) 的处理器到达过程调用时,第二个处理器仍然忙于 fib(1),第一个处理器将挂起 fib(2) 并执行 fib(0) 本身,就像它是唯一的处理器一样。当然,如果有另一个处理器可用,那么它将被调入服务,所有三个处理器将同时执行不同的帧。

您所指的 Wikipedia 中的示例来自 MIT Cilk,它要求生成对 Cilk 函数的所有调用。 Cilk++ 取消了该要求,Cilk++ 演变为英特尔的 Cilk Plus 实施。

请记住,被盗的是延续,而不是生成的函数。在派生函数之前执行代码的工作人员将执行派生函数。 cilk_spawn将延续推送到工人的双端队列,使其可供闲置工人窃取。

考虑在 Cilk Plus 中完全实施 fib:

int fib(int n) {
    if (n < 2)
        return n;
    int x = cilk_spawn fib(n-1);
    int y = fib(n-2);
    cilk_sync;
    return x+y;
}

如果您将 cilk_spawn 放在对 fib 的第二次递归调用上,那么您将允许闲置的工作人员在该调用之后窃取延续。但是那条链立即在 cilk_sync 处结束,所以这是浪费时间。