【问题标题】:How to run code using Node.js Fibers如何使用 Node.js Fibers 运行代码
【发布时间】:2013-01-29 01:06:12
【问题描述】:

我有一个关于 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 代码中发生了什么的任何想法? 并提前感谢...

【问题讨论】:

    标签: javascript node.js node-fibers


    【解决方案1】:

    示例 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. 致电 fiber.run,由于当前光纤已在运行,因此会报错。

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

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

    现在,上面的代码不会发出错误,因为sample 会立即返回。 Fiber里面的执行顺序是:

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

    注意第 4 步是在纤程执行之外完成的。

    示例 2

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


    yield和run函数

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

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

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

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

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

    【讨论】:

    • 很抱歉,如果问题中缺少一点,我真正想要实现的是,如果代码使用f.run() 执行?因为它是思想的核心(从回调中获取值到外部作用域)...
    • 啊,我明白了。但这是一个不同的问题,因为你得到的错误是由于代码中的错误造成的。我相信我的回答正确回答了您的问题,但我将尝试改写部分内容以更好地解释 yield 的功能。
    • 我的解释有帮助吗?
    【解决方案2】:

    正如 Andrew 所解释的,以及我的博文中所暗示的(参见示例后面的句子),您必须创建一个 Fiber 并使用 run() 运行它才能调用 Fiber.yield

    当您运行单个异步调用时,纤程的好处并不明显,但考虑一下您有一个调用 f2 的函数 f1 和调用 f3 的情况。如果f3 调用带有回调的低级异步函数,并且如果您不使用纤程,则必须将f3 转换为带有回调的异步函数,然后通过传染您还必须将f2f1 进入异步函数。使用纤程,您可以将f1f2f3 保留为普通函数(无需回调)。您将需要在f3 中添加一些Fiber.yield() 魔法,您还需要从Fiber 中调用f1,但您无需担心f1f2 中的回调。

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-06
      • 1970-01-01
      • 1970-01-01
      • 2015-04-20
      • 1970-01-01
      • 2011-06-18
      相关资源
      最近更新 更多