简体   繁体   English

如何使用Node.js Fibers运行代码

[英]How to run code using Node.js Fibers

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? 那么,执行run()函数后yield()是否应该等待? Any idea about what is happening in my nodejs code? 关于我的nodejs代码中发生了什么的任何想法? And thanks in advance ... 并提前感谢...

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 bjouhier does not work as is. bjouhier获取的代码不能正常工作。 It was intended to run inside a fiber, like so: 它打算在光纤内部运行,如下所示:

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 . 在光纤上调用run ,运行光纤代码,这是作为回调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. 在分析执行顺序时,人们可能很容易理解为什么。

  1. Set variable f as a fiber. 变量f 设置为光纤。
  2. Run the fiber: 运行光纤:
    1. Set variable fiber pointing to the current running fiber. 设置可变fiber指向当前正在运行的纤维。
    2. Call function sample . 调用函数sample
    3. Call the callback. 拨打
    4. Call fiber.run , which gives the error as the current fiber is already running. 调用 fiber.run ,它会在当前光纤已经运行时给出错误。

The structure of this code is correct, but it assumes sample is some asynchronous function that does not immediately call the callback. 此代码的结构是正确的,但它假定sample是一些不立即调用回调的异步函数。 Let's swap out your sample function by this one: 让我们用这个替换你的sample函数:

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

Now, the above code won't emit an error, as sample immediately returns. 现在,上面的代码不会发出错误,因为sample立即返回。 The order of execution inside the fiber is: 光纤内部的执行顺序是:

  1. Set fiber pointing to the current running fiber. fiber 设置为指向当前正在运行的光纤。
  2. Call sample , which returns without calling the callback (yet). 调用 sample ,它返回而不调用回调(尚未)。
  3. Call `Fiber.yield(), which 'pauses' the current fiber. 调用 `Fiber.yield(),它'暂停'当前的光纤。
  4. After 500 ms, call the callback. 500毫秒后, 调用回调。
  5. Call fiber.run() passing 'this callback', which resumes the fiber. 调用 fiber.run()传递'this callback',它恢复光纤。
  6. Fiber.yield returns, Set str to 'this callback'. Fiber.yield返回, str 设置为'this callback'。
  7. Log the string to console. 登录到控制台的字符串。

Observe that step 4 is done outside the execution of the fiber. 观察到步骤4在光纤执行之外完成。

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. 而在第一个例子中没有运行光纤(因此fiber 未定义 ),在第二个例子中,出于同样的原因抛出了错误。 Again, the code needs to run inside a fiber. 同样,代码需要在光纤内部运行。


The function of yield and 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 ' yielding control', 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: 将值传入和传出光纤的机制是通过yield和run的相互作用:

  • An argument given to run (which is outside the fiber), is returned by yield (inside the fiber). 给出run的参数(在光纤之外)由yield (光纤内部)返回。
  • An argument given to yield (inside the fiber), is returned by run (outside the fiber). yield (光纤内部)的参数由run (光纤外)返回。

For an example, look at the incremental generator on the github repository of node-fibers . 例如,查看node-fiber的github存储库增量生成器。 Additionally, observe that our Example 1, the callback given to sample is essentially ran outside the fiber, as it is ran on the next tick (viz. the async nature of setTimeout ). 另外,观察我们的示例1,给予sample的回调基本上是在光纤之外运行,因为它在下一个tick(即setTimeout的异步性质)上运行。

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 . 正如安德鲁所解释的那样,并且在我的博客文章中暗示(参见示例后面的句子),您必须创建一个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 . 当你有一个异步调用来运行时,光纤的好处并不明显,但考虑一下你有一个函数f1调用调用f3 f2 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. 如果f3使用回调调用低级别异步函数,并且如果不使用光纤,则必须将f3转换为带回调的异步函数,然后通过传染,您还必须将f2f1转换为异步函数。 With fibers, you can keep f1 , f2 and f3 as normal functions (without callback). 使用光纤,您可以将f1f2f3保持为正常功能(无回调)。 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 . 你需要在f3一些Fiber.yield()魔法,你还需要从Fiber内部调用f1 ,但你不必担心f1f2中的回调。

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 futures library instead. 另外,编写光纤的Marcel建议您不要在代码中直接使用Fiber.yield() ,而是使用期货库。 It's interesting to play with Fiber.yield to understand what fibers are made of but I encourage you to use the futures library for a real project. Fiber.yield一起使用可以了解纤维是由什么制成的,但我鼓励您将期货库用于实际项目。 It will also help you parallelize your code. 它还可以帮助您并行化代码。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM