javascript 如何使用 Node.js Fibers 运行代码
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14854346/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to run code using Node.js Fibers
提问by megamoth
I have a question about Nodejs Fibers(which is absolute new for me) ... I have this tutorial for Nodejs Fibers, http://bjouhier.wordpress.com/2012/03/11/fibers-and-threads-in-node-js-what-for/, and there was an example in here it says
我有一个关于 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!
Now based on this Example I created my own version of the code like this,
现在基于此示例,我创建了自己的代码版本,如下所示,
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);
but this gives me an Error of,
但这给了我一个错误,
/home/ubuntu/Tasks/ServerFilteringV1/test.js:28
fiber.run(string);
^
TypeError: Cannot call method 'run' of undefined
And I have another case which will run a function after 1000 ms with the callback inside (I have done this to test functions with long time executions before a callback),
我还有另一个案例,它将在 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);
This code in here gives me another Error ,
这里的代码给了我另一个错误,
/home/ubuntu/Tasks/ServerFilteringV1/test.js:30
var string = Fiber.yield();
^
Error: yield() called with no fiber running
Well, should the yield() wait after a run() function is executed? Any idea about what is happening in my nodejs code? And thanks in advance ...
那么,yield() 应该在 run() 函数执行后等待吗?知道我的 nodejs 代码中发生了什么吗?并提前致谢...
回答by Andrew
Example 1
示例 1
A fiber is a sort of lightweight thread of execution. Like real threads and processes, a fiber must be given a block of code to execute upon run. The code as you took it from bjouhierdoes not work as is. It was intended to run inside a fiber, like so:
纤程是一种轻量级的执行线程。就像真正的线程和进程一样,必须为纤程提供一个代码块以在运行时执行。您从bjouhier 获取的代码无法按原样运行。它旨在在光纤内部运行,如下所示:
var f = Fiber(function() {
var fiber = Fiber.current;
sample(function(str) {
fiber.run(string);
});
var str = Fiber.yield();
console.log(str);
});
f.run();
Calling run
on the fiber, well, runs the fiber code, which was given as callback to Fiber
. The above code, however, will also give an error (stating the fiber is already running). One might easily see why when analysing the order of execution.
调用run
纤程,运行纤程代码,该代码作为对Fiber
. 但是,上面的代码也会出错(说明光纤已经在运行)。在分析执行顺序时,人们可能很容易看出原因。
- Setvariable
f
as a fiber. - Runthe fiber:
- Setvariable
fiber
pointing to the current running fiber. - Callfunction
sample
. - Callthe callback.
- Call
fiber.run
, which gives the error as the current fiber is already running.
- Setvariable
- 将变量设置
f
为光纤。 - 运行光纤:
- 设置变量
fiber
指向当前运行的光纤。 - 调用函数
sample
。 - 调用回调。
- 调用
fiber.run
,这会给出错误,因为当前光纤已经在运行。
- 设置变量
The structure of this code is correct, but it assumes sample
is some asynchronous function that does not immediately call the callback. Let's swap out your sample
function by this one:
这段代码的结构是正确的,但它假设sample
是一些不会立即调用回调的异步函数。让我们sample
用这个换掉你的功能:
function sample(callback) {
setTimeout(function() {
callback("this callback");
}, 500);
}
Now, the above code won't emit an error, as sample
immediately returns. The order of execution inside the fiber is:
现在,上面的代码不会发出错误,因为会sample
立即返回。光纤内部的执行顺序为:
- Set
fiber
pointing to the current running fiber. - Call
sample
, which returns without calling the callback (yet). - Call`Fiber.yield(), which 'pauses' the current fiber.
- After 500 ms, callthe callback.
- Call
fiber.run()
passing 'this callback', which resumes the fiber. Fiber.yield
returns, Setstr to 'this callback'.- Logthe string to console.
- 设置
fiber
指向当前运行的光纤。 - Call
sample
,它返回而不调用回调(尚未)。 - 调用“Fiber.yield()”,它“暂停”当前的光纤。
- 500 毫秒后,调用回调。
- 调用
fiber.run()
传递“这个回调”,它恢复光纤。 Fiber.yield
返回,将str设置为“此回调”。- 登录串到控制台。
Observe that step 4 is done outside the execution of the fiber.
观察到第 4 步是在 Fiber 执行之外完成的。
Example 2
示例 2
Whereas in the first example there was no running fiber (and therefore fiber
was undefined), in the second example the error is thrown for the same reason. Again, the code needs to run inside a fiber.
而在第一个示例中没有运行的光纤(因此fiber
是undefined),在第二个示例中,由于相同的原因抛出错误。同样,代码需要在纤程中运行。
The function of yield and run
yield 和 run 的函数
A fiber must cooperatively give control to another fiber (or the main line of execution). Compare that to the preemptive nature of threads and processes. The giving up control is what is meant by 'yieldingcontrol', and in this case is done by Fiber.yield()
.
一个纤程必须协作地将控制权交给另一个纤程(或主执行线)。将其与线程和进程的抢占性质进行比较。该放弃控制权是什么是“意味着产生控制”,在这种情况下被完成Fiber.yield()
。
To continue execution (directly after the point of where the fiber yielded), one must call run()
on the fiber.
要继续执行(直接在光纤产生的点之后),必须调用run()
光纤。
The mechanism to pass values in and out of the fiber is through the interplay of yield and run:
将值传入和传出 Fiber 的机制是通过 yield 和 run 的相互作用:
- An argument given to
run
(which is outside the fiber), is returned byyield
(inside the fiber). - An argument given to
yield
(inside the fiber), is returned byrun
(outside the fiber).
- 提供给
run
(在光纤外部)的参数由yield
(在光纤内部)返回。 - 给
yield
(光纤内部)的参数由run
(光纤外部)返回。
For an example, look at the incremental generator on the github repository of node-fibers. Additionally, observe that our Example 1, the callback given to sample
is essentially ran outsidethe fiber, as it is ran on the next tick (viz. the async nature of setTimeout
).
例如,查看node-fibers 的 github 存储库上的增量生成器。此外,请注意我们的示例 1,给定的回调sample
基本上在纤程之外运行,因为它在下一个滴答运行(即 的异步性质setTimeout
)。
回答by Bruno Jouhier
As explained by Andrew, and as hinted in my blog post (see the sentence that follows the example), you have to create a Fiber
and run it with run()
to be able to call Fiber.yield
.
正如 Andrew 所解释的,以及我的博客文章中所暗示的(参见示例后面的句子),您必须创建一个Fiber
并运行它run()
才能调用Fiber.yield
.
The benefit of fibers is not obvious when you have a single async call to run, but consider the case where you have a function f1
that calls f2
that calls f3
. If f3
calls a low-level async function with a callback and if you do not use fibers, you have to turn f3
into an async function with a callback, and then by contagion you also have to turn f2
and f1
into async functions. With fibers, you can keep f1
, f2
and f3
as normal functions (without callback). You will need some Fiber.yield()
magic inside f3
and you will also need to call f1
from inside a Fiber
but you don't need to worry about callbacks in the bodies of f1
and f2
.
纤维的好处并不明显,当你有一个异步调用运行,但考虑的情况下你有一个功能f1
是通话f2
的呼叫f3
。如果f3
调用一个回调低级别的异步功能,如果你不使用的纤维,你必须把f3
被传染成一个异步函数的回调,然后你还必须把f2
和f1
成异步功能。使用纤程,您可以保留f1
,f2
和f3
作为正常功能(无回调)。您将需要一些Fiber.yield()
魔法,f3
并且您还需要f1
从 a 内部调用,Fiber
但您无需担心f1
and主体中的回调f2
。
So fibers really shine when you have multiple layers of code or complex control flow between your high level functions and the low level async functions that they call.
因此,当您的高级函数和它们调用的低级异步函数之间有多层代码或复杂的控制流时,纤维真的很出色。
Also, Marcel, who wrote fibers, recommends that you don't use Fiber.yield()
directly in your code but that you use his futureslibrary instead. It's interesting to play with Fiber.yield
to understand what fibers are made of but I encourage you to use the futureslibrary for a real project. It will also help you parallelize your code.
此外,编写 Fiber 的 Marcel 建议您不要Fiber.yield()
直接在代码中使用,而应使用他的futures库。Fiber.yield
了解纤维是由什么组成的很有趣,但我鼓励您将期货库用于实际项目。它还将帮助您并行化您的代码。