3

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! 

この例に基づいて、次のようなコードの独自のバージョンを作成しました。

  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

では、run() 関数が実行された後、yield() は待機する必要がありますか? 私のnodejsコードで何が起こっているかについて何か考えはありますか? そして、前もって感謝します...

4

2 に答える 2

21

例 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. Call fiber.run、現在のファイバーが既に実行されているため、エラーが発生します。

このコードの構造は正しいですがsample、コールバックをすぐには呼び出さない非同期関数であると想定しています。sampleこれで関数を交換しましょう:

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

これで、上記のコードはエラーを出さず、sampleすぐに戻ります。ファイバー内での実行順序は次のとおりです。

  1. fiber現在実行中のファイバーを指すように設定します。
  2. Call sample、コールバックを呼び出さずに戻ります (まだ)。
  3. 現在のファイバーを「一時停止」する「Fiber.yield()」を呼び出します。
  4. 500 ミリ秒後、コールバックを呼び出します。
  5. fiber.run()ファイバーを再開する「このコールバック」を渡す呼び出し。
  6. Fiber.yield戻ります。str を「このコールバック」に設定します。
  7. 文字列をコンソールに記録します。

ステップ 4 がファイバーの実行外で行われることに注意してください。

例 2

最初の例では実行中のファイバーがありませんでしたが (したがってundefinedfiberでした)、2 番目の例では同じ理由でエラーがスローされます。繰り返しますが、コードはファイバー内で実行する必要があります。


yield と run の機能

ファイバーは、協調して別のファイバー (または実行のメイン ライン) に制御を与える必要があります。それを、スレッドとプロセスのプリエンプティブな性質と比較してください。制御を放棄することは、「制御を譲る」が意味するものあり、この場合は によって行われFiber.yield()ます。

実行を継続するには (ファイバーが生成された時点の直後)、ファイバーを呼び出す必要がありますrun()

ファイバーの内外に値を渡すメカニズムは、収量と実行の相互作用によるものです。

  • (ファイバーの外側にある) に与えられた引数は、 (ファイバーの内側)runによって返されます。yield
  • (ファイバーの内側) に与えられた引数は、(ファイバーの外側)yieldによって返されrunます。

例として、node-fibers の github リポジトリにあるインクリメンタル ジェネレーターを見てください。さらに、例 1 に与えられたコールバックsampleは、次のティックで実行されるため、本質的にファイバーの外側で実行されることに注意してください (つまり、 の非同期性setTimeout)。

于 2013-03-03T17:58:23.147 に答える
0

Andrew が説明したように、また私のブログ投稿 (例に続く文を参照) で示唆されているように、を呼び出すには、 を作成してFiberで実行する必要があります。run()Fiber.yield

実行する非同期呼び出しが 1 つの場合、ファイバーの利点は明らかではありませんが、をf1呼び出す関数がある場合を考えてみてください。コールバックを使用して低レベルの非同期関数を呼び出し、ファイバーを使用しない場合は、コールバックを使用して非同期関数に変換する必要があり、伝染によって非同期関数にも変換する必要があります。ファイバーを使用すると、とを通常の関数 (コールバックなし) として保持できます。内部にいくつかの魔法が必要であり、 a の内部からも呼び出す必要がありますが、との本体でのコールバックについて心配する必要はありません。f2f3f3f3f2f1f1f2f3Fiber.yield()f3f1Fiberf1f2

そのため、高レベルの関数とそれらが呼び出す低レベルの非同期関数の間に複数のコード レイヤーまたは複雑な制御フローがある場合、ファイバーは真価を発揮します。

また、ファイバーを書いた Marcel はFiber.yield()、コードで直接使用するのではなく、代わりに彼の先物ライブラリーを使用することを推奨しています。Fiber.yield繊維が何でできているかを理解するのは興味深いことですが、実際のプロジェクトでは先物ライブラリを使用することをお勧めします。コードの並列化にも役立ちます。

于 2013-03-07T21:38:45.757 に答える