3

我有一个关于 Nodejs Fibers 的问题(这对我来说绝对是新的)......我有这个 Nodejs Fibers 教程,http: //bjouhier.wordpress.com/2012/03/11/fibers-and-threads-in- node-js-what-for/,这里有一个例子,它说

    var fiber = Fiber.current;
    db.connect(function(err, conn) {
    if (err) return fiber.throwInto(err);
       fiber.run(conn);
    });
   // Next line will yield until fiber.throwInto 
   // or fiber.run are called
   var c = Fiber.yield();
   // If fiber.throwInto was called we don't reach this point 
   // because the previous line throws.
   // So we only get here if fiber.run was called and then 
   // c receives the conn value.
   doSomething(c);
   // Problem solved! 

现在基于这个示例,我创建了自己的代码版本,如下所示,

  var Fiber = require('fibers');

  function sample(callback){
     callback("this callback");
  }

  var fiber = Fiber.current;
  sample(function(string){
     fiber.run(string);
  });
  var string = Fiber.yield();
  console.log(string);

但这给了我一个错误,

/home/ubuntu/Tasks/ServerFilteringV1/test.js:28
    fiber.run(string);
      ^
TypeError: Cannot call method 'run' of undefined

我还有另一种情况,它将在 1000 毫秒后运行一个带有回调的函数(我这样做是为了在回调之前测试长时间执行的函数),

var Fiber = require('fibers');

function forEach(callback){
   setTimeout(function(){
       callback("this callback");
   },1000);
}


var fiber = Fiber.current;
forEach(function(string){
   fiber.run(string);
});
var string = Fiber.yield();
console.log(string);

这里的代码给了我另一个错误,

/home/ubuntu/Tasks/ServerFilteringV1/test.js:30
var string = Fiber.yield();
                    ^
Error: yield() called with no fiber running

那么,yield() 是否应该在 run() 函数执行后等待?关于我的 nodejs 代码中发生了什么的任何想法?并提前感谢...

4

2 回答 2

21

示例 1

纤程是一种轻量级的执行线程。像真正的线程和进程一样,必须为纤程提供一段代码以在运行时执行。您从bjouhier 获取的代码不能按原样工作。它旨在在纤维内运行,如下所示:

var f = Fiber(function() {
    var fiber = Fiber.current;

    sample(function(str) {
        fiber.run(string);
    });

    var str = Fiber.yield();
    console.log(str);
});

f.run();

调用run纤程,运行纤程代码,作为回调给Fiber. 然而,上面的代码也会给出一个错误(说明光纤已经在运行)。在分析执行顺序时,人们可能很容易明白为什么。

  1. 变量设置f为光纤。
  2. 运行光纤:
    1. 设置变量fiber指向当前运行的光纤。
    2. 调用函数sample
    3. 调用回调。
    4. Call fiber.run,当当前光纤已经在运行时,它会给出错误。

这段代码的结构是正确的,但它假设sample是一些不立即调用回调的异步函数。让我们用这个替换你的sample函数:

function sample(callback) {
    setTimeout(function() {
        callback("this callback");
    }, 500);
}

现在,上面的代码不会发出错误,而是sample立即返回。光纤内部的执行顺序是:

  1. 设置 fiber指向当前运行的光纤。
  2. Call sample,它返回而不调用回调(还)。
  3. 调用`Fiber.yield(),它会“暂停”当前的光纤。
  4. 500 毫秒后,调用回调。
  5. 调用 fiber.run()传递“此回调”,恢复光纤。
  6. Fiber.yield返回,str 设置为“此回调”。
  7. 将字符串记录到控制台。

请注意,步骤 4 是在光纤执行之外完成的。

示例 2

虽然在第一个示例中没有运行光纤(因此fiber未定义,但在第二个示例中,由于相同的原因引发了错误。同样,代码需要在光纤内运行。


产量和运行功能

一个纤程必须协同控制另一个纤程(或主执行线)。将其与线程和进程的抢占性质进行比较。放弃控制权是“让出控制权”的意思在这种情况下由Fiber.yield().

要继续执行(直接在光纤产生的点之后),必须调用run()光纤。

将值传入和传出光纤的机制是通过产量和运行的相互作用:

  • 给定的参数run(在光纤外)由yield(在光纤内)返回。
  • yield(光纤内)的参数由run(光纤外)返回。

例如,查看node-fibers 的 github 存储库中的增量生成器。此外,请注意我们的示例 1,给定的回调sample实际上是在光纤之外运行的,因为它在下一个滴答时运行(即 的异步性质setTimeout)。

于 2013-03-03T17:58:23.147 回答
0

正如 Andrew 所解释的,并且正如我的博客文章中所暗示的那样(请参阅示例后面的句子),您必须创建一个Fiber并运行它run()才能调用Fiber.yield.

当您运行单个异步调用时,fiber 的好处并不明显,但请考虑您有一个f1调用f2该调用的函数的情况f3。如果f3使用回调调用低级异步函数并且不使用光纤,则必须将其f3转换为带有回调的异步函数,然后通过传染您还必须将其f2转换f1为异步函数。使用纤维,您可以将f1,f2和保留f3为正常功能(没有回调)。您将需要一些Fiber.yield()内部魔法f3,您还需要f1从内部调用 aFiber但您不必担心 and 主体中的f1回调f2

因此,当您在高级函数和它们调用的低级异步函数之间有多层代码或复杂的控制流时,纤维真的会发光。

此外,编写纤维的 Marcel 建议您不要Fiber.yield()直接在代码中使用,而是使用他的期货库。Fiber.yield了解纤维是由什么制成的很有趣,但我鼓励您将期货库用于实际项目。它还将帮助您并行化您的代码。

于 2013-03-07T21:38:45.757 回答