2016-05-06 1 views
1

私はJS /ノードの初心者です.Javascriptの "並行性"のテーマの周りに頭を浮かべています。私は今までにコールバックをかなり快適に思っていますが、これが私のシナリオに入る方法ではないと私は思います。基本的に私は、main processが作業を続けている間に、私は一つずつ処理する必要がある反復的な高価な仕事(worker)を持っています。ここに最小限のテストです。node.jsにバックグラウンドシングルスレッドFIFOジョブキューを作成するには

/* 
* We have a worker function that does some expensive task, e.g., an 
* I/O task or something else. 
*/ 
worker = function (jobId) { 

    // It will take something between 1 and 2 seconds. 
    var runtime = Math.floor((Math.random() * 1000) + 1000); 
    console.log("started job #" + jobId + " (" + runtime + " ms)"); 

    // Then the worker will do something for a while ... 
    setTimeout(
     function() { 
      // .. and at some point it'll be finished. 
      console.log("finished job #" + jobId); 
     }, runtime 
    ); 

}; 

/* 
* We obviously have a main process that meanwhile does other stuff 
* like processed user interactions. In this case we call this until 
* some artificial tickets are used. 
*/ 
mainprocess = function (tickets) { 

    // Simulate some processing time .. 
    var runtime = Math.floor((Math.random() * 500)); 
    setTimeout(
     function() { 
      console.log("main process #" + tickets + " (" + runtime + " ms)"); 
      if (tickets > 0) { 
       tickets--; 
       mainprocess(tickets); 
      } 
     }, runtime 
    ); 
} 

// At some point in the code we create workers and we want to make sure 
// they're processed in the *order of creation* and *one after another* 
// without blocking the main process ... 
for (var i = 1; i <= 10; i++) { 
    worker(i); 
}; 

// ... and the some other stuff will happen for a while! 
mainprocess(10); 

// .. 

コードは、現在、私は本当に知らない

started job #1 (1751 ms) 
started job #2 (1417 ms) 
... 
started job #9 (1050 ms) 
started job #10 (1864 ms) 
main process #10 (142 ms) 
main process #9 (228 ms) 
main process #8 (149 ms) 
main process #7 (88 ms) 
main process #6 (410 ms) 
finished job #9 
finished job #5 
main process #5 (265 ms) 
finished job #2 
main process #4 (270 ms) 
finished job #7 
finished job #3 
finished job #1 
... 
main process #1 (486 ms) 
main process #0 (365 ms) 

...のようなものを出力し、メインプロセスが継続されるように、コードを変更する方法をワーカースレッドがで実行されている間作成順(現在のところ、正しい順序でのみ開始されています)と(順番に並んでいます)(現在はすべて並列)です。希望の出力は..

started job #1 (1384 ms) 
main process #10 (268 ms) 
main process #9 (260 ms) 
main process #8 (216 ms) 
main process #7 (93 ms) 
main process #6 (160 ms) 
main process #5 (269 ms) 
main process #4 (44 ms) 
finished job #1 
started job #2 (1121 ms) 
main process #3 (172 ms) 
main process #2 (170 ms) 
main process #1 (437 ms) 
finished job #2 
started job #3 (1585 ms) 
main process #0 (460 ms) 
finished job #3 
started job #4 (1225 ms) 
finished job #4 
started job #5 (1300 ms) 
finished job #5 

助けてください。

答えて

1

さて、私はそれを理解しました。拡張コードとコメントコードはのjavacriptの組み込みの約束を使用しますが、QまたはBluebirdまたは他のノード互換性のある約束ライブラリでも同じことを達成できます。ノード環境でjquery $.Deferredオブジェクトを使用できないことに注意してください。必要に応じて

/* 
* We have a worker function that does some expensive task, e.g., an 
* I/O task or something else. 
*/ 
worker = function (jobId) { 

    // we need to put it into a new promise object 
    return new Promise(function(resolve, reject) { 

     // It will take something between 1 and 2 seconds. 
     var runtime = Math.floor((Math.random() * 1000) + 1000); 
     console.log("started job #" + jobId + " (" + runtime + " ms)"); 

     // Then the worker will do something for a while ... 
     setTimeout(
      function() { 
       // .. and at some point it'll be finished. 
       console.log("finished job #" + jobId); 
       // .. now we have to resolve the promise!! 
       resolve("resolved job #" + jobId); 
      }, runtime 
     ); 

    }); 
}; 


/* 
* We obviously have a main process that meanwhile does other stuff 
* like processed user interactions. In this case we call this until 
* some artificial tickets are used. 
*/ 
mainprocess = function (tickets) { 

    // Simulate some processing time .. 
    var runtime = Math.floor((Math.random() * 500)); 
    setTimeout(
     function() { 
      console.log("main process #" + tickets + " (" + runtime + " ms)"); 
      if (tickets > 0) { 
       tickets--; 
       mainprocess(tickets); 
      } 
     }, runtime 
    ); 
} 

// create a sequence with a resolved promise 
var sequence = Promise.resolve(); 

// At some point in the code we create workers and we want to make sure 
// they're processed in the *order of creation* and *one after another* 
// without blocking the main process ... 
for (var i = 1; i <= 10; i++) { 
    // create an IIFE so that the current "i" gets its own 
    // closure when it will be used later (otherwise all job ids 
    // would be "11" on invokation of the worker). 
    (function() { 
     var jobId = i; 
     // add a new promise after the previous promise resolved 
     sequence = sequence.then(
      function(result) { 
       // handle result later 
       return worker(jobId); 
       // return just added the next promise to the chain! 
      }, 
      function(err) { 
       // handle error later 
      } 
     ); 
    })(); // END IIFE 
}; 

// ... and the some other stuff will happen for a while! 
mainprocess(10); 

// .. 

出力は次のようになります。

started job #1 (1384 ms) 
main process #10 (268 ms) 
main process #9 (260 ms) 
main process #8 (216 ms) 
main process #7 (93 ms) 
main process #6 (160 ms) 
main process #5 (269 ms) 
main process #4 (44 ms) 
finished job #1 
started job #2 (1121 ms) 
main process #3 (172 ms) 
main process #2 (170 ms) 
main process #1 (437 ms) 
finished job #2 
started job #3 (1585 ms) 
main process #0 (460 ms) 
finished job #3 
started job #4 (1225 ms) 
finished job #4 
started job #5 (1300 ms) 
finished job #5 
... 

私は洞察を提供し、以下の記事に大きな賛辞を与えることがあります。

0

最初にメインスレッドを実行し、作成した順番でワーカースレッドを実行する場合は、ワーカー(i)を呼び出す場所のループをセットタイムアウト関数に配置し、約1000ms。その後、完成したジョブにも1000msの一定の遅延が与えられ、作成された順序で実行されます。 リンクを確認してください:jsfiddle.net/som99/weq87xnd/2/

+0

私は実際には一定の遅延を使用する考え方は嫌いです。実際のアプリケーションでは、 'worker'関数が一定時間実行されることを保証することはできません。もしそうであれば時間を無駄にし、はいの場合はプロセスを中断します。私は、条件付き解決策がより適切であるべきだと考えています。したがって、私は現在、約束を守ろうとしています。 –

+0

しかし、以下の解決策では、メインスレッドはバックグラウンドスレッドとして実行されていません。現実のアプリケーションのシナリオでは、メインスレッドがまだ生きている間に、ワーカーまたはセカンダリスレッドがフォアグラウンドで実行されます。メインスレッドが最初に完了した場合、ワーカースレッドまたはサービススレッドはどのように実行されますか? – user2602433

+0

メインの「スレッド」は、ユーザーの操作などを処理するスレッドです。ワーカー「スレッド」は高価なタスクを処理します。前景や背景がなく、生きている。すべてがイベントループ内の単一のスレッドで実行されます。ここでは、2つの異なるタスクが並行して動作するように見えます。単に例を実行するか、出力を見てください。すべての作業者が完了し、メインプロセスにチケットが残っていない場合、プログラムは終了します。 –

関連する問題