如何使用Node.js Fibers运行代码
我有一个关于Nodejs光纤的问题(这对我来说是绝对新的)…我有Nodejs光纤的这个教程, 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!
现在基于这个例子,我创build了我自己的代码版本,
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毫秒之后的callback函数里运行一个函数(我已经在callback函数之前用长时间的执行来testing函数了),
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
那么,应该在run()函数执行之后等待yield()? 任何有关我的nodejs代码发生什么想法? 并提前感谢…
例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
调用run
的是光纤代码,这个代码是作为Fiber
callback给出的。 上面的代码也会给出一个错误(说明光纤已经在运行)。 在分析执行顺序时,可以很容易地看到为什么。
- 将variables
f
设置为光纤。 - 运行光纤:
- 设置指向当前运行光纤的可变光纤。
- 调用函数
sample
。 - 调用callback。
- 调用
fiber.run
,在当前光纤已经运行的情况下给出错误。
这个代码的结构是正确的,但是它假设sample
是一些不立即调用callback的asynchronous函数。 我们用这个换掉你的sample
函数:
function sample(callback) { setTimeout(function() { callback("this callback"); }, 500); }
现在,上面的代码不会发出错误,因为sample
立即返回。 光纤内的执行顺序是:
- 将
fiber
指向当前正在运行的光纤。 - 调用
sample
,它将返回而不调用callback(还)。 - 调用 `Fiber.yield(),它暂停当前的光纤。
- 在500毫秒后, 调用callback。
- 调用
fiber.run()
传递'this callback',它将恢复光纤。 -
Fiber.yield
返回, 将 str 设置为“this callback”。 - 将stringlogging到控制台。
请注意,步骤4是在光纤执行之外完成的。
例2
而在第一个例子中,没有运行的光纤(因此fiber
未定义 ),在第二个例子中,由于相同的原因抛出错误。 同样,代码需要在光纤内运行。
产量和运行的function
光纤必须协同控制另一根光纤(或执行的主线)。 将它与线程和进程的优先性进行比较。 放弃控制是“ 屈服控制”的意思,在这种情况下,由Fiber.yield()
。
要继续执行(直接在光纤放置点之后),必须在光纤上调用run()
。
使价值进出纤维的机制是通过产量和运行的相互作用:
-
run
的参数(在纤维之外)是由yield
(在纤维内部)返回的。 -
yield
(在纤维内部)的一个论据是由run
(在纤维之外)返回的。
例如,查看github节点光纤存储库上的增量生成器。 此外,观察我们的例子1,给sample
的callback基本上跑到了光纤外面 ,因为它在下一个刻度上运行(即setTimeout
的asynchronous性质)。
正如Andrew所解释的那样,正如我在博客文章中所暗示的那样(请参阅下面的例子),您必须创build一个Fiber
并使用run()
运行它,以便能够调用Fiber.yield
。
当你有一个单独的asynchronous调用运行时,光纤的好处并不明显,但考虑一下你有一个调用f2
调用f3
的函数f1
的情况。 如果f3
使用callback调用低级别的asynchronous函数,并且如果不使用光纤,则必须将f3
转换为具有callback的asynchronous函数,然后通过传染,还必须将f2
和f1
变为asynchronous函数。 使用光纤,您可以将f1
, f2
和f3
保留为正常function(无回叫)。 您需要在f3
内部使用一些Fiber.yield()
魔术,而且您还需要从Fiber
内部调用f1
,但是您不必担心f1
和f2
的主体中的callback。
因此,当您的高级function与他们所调用的低级别asynchronousfunction之间有多层代码或复杂的控制stream程时,光纤会发光。
而且,编写纤维的Marcelbuild议您不要直接在代码中使用Fiber.yield()
,而是使用期货库。 用Fiber.yield
来理解纤维是由什么材料制成的,但我鼓励你使用期货库Fiber.yield
一个真实的项目。 它也将帮助你并行化你的代码。