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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-26 22:45:15  来源:igfitidea点击:

How to run code using Node.js Fibers

javascriptnode.jsnode-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 runon 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. 但是,上面的代码也会出错(说明光纤已经在运行)。在分析执行顺序时,人们可能很容易看出原因。

  1. Setvariable fas a fiber.
  2. Runthe fiber:
    1. Setvariable fiberpointing to the current running fiber.
    2. Callfunction sample.
    3. Callthe callback.
    4. Callfiber.run, which gives the error as the current fiber is already running.
  1. 变量设置f为光纤。
  2. 运行光纤:
    1. 设置变量fiber指向当前运行的光纤。
    2. 调用函数sample
    3. 调用回调。
    4. 调用fiber.run,这会给出错误,因为当前光纤已经在运行。

The structure of this code is correct, but it assumes sampleis some asynchronous function that does not immediately call the callback. Let's swap out your samplefunction by this one:

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

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

Now, the above code won't emit an error, as sampleimmediately returns. The order of execution inside the fiber is:

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

  1. Setfiberpointing to the current running fiber.
  2. Callsample, which returns without calling the callback (yet).
  3. Call`Fiber.yield(), which 'pauses' the current fiber.
  4. After 500 ms, callthe callback.
  5. Callfiber.run()passing 'this callback', which resumes the fiber.
  6. Fiber.yieldreturns, Setstr to 'this callback'.
  7. Logthe string to console.
  1. 设置fiber指向当前运行的光纤。
  2. Callsample,它返回而不调用回调(尚未)。
  3. 调用“Fiber.yield()”,它“暂停”当前的光纤。
  4. 500 毫秒后,调用回调。
  5. 调用fiber.run()传递“这个回调”,它恢复光纤。
  6. Fiber.yield返回,str设置为“此回调”。
  7. 登录串到控制台。

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 fiberwas undefined), in the second example the error is thrown for the same reason. Again, the code needs to run inside a fiber.

而在第一个示例中没有运行的光纤(因此fiberundefined),在第二个示例中,由于相同的原因抛出错误。同样,代码需要在纤程中运行。



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 by yield(inside the fiber).
  • An argument given to yield(inside the fiber), is returned by run(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 sampleis 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 Fiberand 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 f1that calls f2that calls f3. If f3calls a low-level async function with a callback and if you do not use fibers, you have to turn f3into an async function with a callback, and then by contagion you also have to turn f2and f1into async functions. With fibers, you can keep f1, f2and f3as normal functions (without callback). You will need some Fiber.yield()magic inside f3and you will also need to call f1from inside a Fiberbut you don't need to worry about callbacks in the bodies of f1and f2.

纤维的好处并不明显,当你有一个异步调用运行,但考虑的情况下你有一个功能f1是通话f2的呼叫f3。如果f3调用一个回调低级别的异步功能,如果你不使用的纤维,你必须把f3被传染成一个异步函数的回调,然后你还必须把f2f1成异步功能。使用纤程,您可以保留f1,f2f3作为正常功能(无回调)。您将需要一些Fiber.yield()魔法,f3并且您还需要f1从 a 内部调用,Fiber但您无需担心f1and主体中的回调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.yieldto 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了解纤维是由什么组成的很有趣,但我鼓励您将期货库用于实际项目。它还将帮助您并行化您的代码。