web-dev-qa-db-ja.com

Node.JSでsetTimeoutはどのように機能しますか?

一度実行されるとキューに置かれますが、キューにはXミリ秒後に正確に呼び出されるという保証がありますか?または、キューの上位にある他の重いタスクがそれを遅らせますか?

105
MyCodeGone

SetTimeoutのセマンティクスはWebブラウザーのセマンティクスとほぼ同じです。タイムアウト引数は最小実行前に待機するミリ秒数であり、保証ではありません。さらに、0、非数値、または負の数値を渡すと、最小ミリ秒待機します。 Nodeでは、これは1ミリ秒ですが、ブラウザでは50ミリ秒になります。

これは、JavaScriptによるJavaScriptのプリエンプションがないためです。この例を考えてみましょう:

setTimeout(function () {
  console.log('boo')
}, 100)
var end = Date.now() + 5000
while (Date.now() < end) ;
console.log('imma let you finish but blocking the event loop is the best bug of all TIME')

ここでの流れは次のとおりです。

  1. 100msのタイムアウトをスケジュールします。
  2. 5000ミリ秒間のビジーウェイト。
  3. イベントループに戻ります。保留中のタイマーを確認して実行します。

そうでない場合は、JavaScriptのビットをもう1つ「中断」させることができます。このようなコードが推論するのが極端に困難になるのを防ぐために、ミューテックスやセマフォーなどを設定する必要があります。

var a = 100;
setTimeout(function () {
  a = 0;
}, 0);
var b = a; // 100 or 0?

NodeのJavaScript実行のシングルスレッド化により、他のほとんどのスタイルの並行処理よりも作業がはるかに簡単になります。もちろん、トレードオフは、プログラムの不正な動作が無限ループですべてをブロックする可能性があることです。

これは、プリエンプションの複雑さよりも戦いに適した悪魔ですか?場合によります。

157
isaacs

ノンブロッキングの考え方は、ループの反復が速いということです。そのため、各ティックを反復するには、setTimeoutが妥当な精度(100ミリ秒以下でオフになる可能性があります)以内に正確になるまで十分に短い時間がかかります。

理論上はあなたは正しい。アプリケーションを作成してティックをブロックすると、setTimeoutsが遅延します。あなたが質問に答えるために、誰がsetTimeoutsを時間通りに実行することを保証できますか?ノンブロッキングコードを記述することで、ほとんどの妥当な精度まで精度を制御できます。

Javascriptがコード実行に関して「シングルスレッド」である限り(Webワーカーなどを除く)、それは常に発生します。ほとんどの場合、シングルスレッドの性質は非常に単純化されていますが、成功するにはノンブロッキングイディオムが必要です。

ブラウザまたはノードでこのコードを試してみると、正確性が保証されていないことがわかります。逆に、setTimeoutは非常に遅くなります。

var start = Date.now();

// expecting something close to 500
setTimeout(function(){ console.log(Date.now() - start); }, 500);

// fiddle with the number of iterations depending on how quick your machine is
for(var i=0; i<5000000; ++i){}

インタープリターがループを最適化しない限り(クロームでは行われません)、何千ものループが得られます。ループを削除すると、鼻の上に500が表示されます...

40
davin

コードが確実に実行される唯一の方法は、setTimeoutロジックを別のプロセスに配置することです。

子プロセスモジュールを使用して、ロジックを実行する新しいnode.jsプログラムを生成し、何らかのストリーム(おそらくtcp)を介してそのプロセスにデータを渡します。

この方法では、メインプロセスで長いブロックコードが実行されている場合でも、子プロセスは既に開始され、setTimeoutを新しいプロセスと新しいスレッドに配置しているため、期待どおりに実行されます。

さらに複雑なのは、プロセスよりも多くのスレッドを実行しているハードウェアレベルであるため、コンテキストの切り替えにより、予想されるタイミングから(ごくわずかな)遅延が発生します。これは無視できるはずであり、重要な場合は、何をしようとしているのか、なぜそのような精度が必要なのか、代わりにジョブを実行するために利用可能なリアルタイムの代替ハードウェアの種類を真剣に検討する必要があります。

一般に、子プロセスを使用し、複数のノードアプリケーションを別々のプロセスとしてロードバランサーまたは共有データストレージ(redisなど)と一緒に実行することは、コードのスケーリングにとって重要です。

8
Raynos

setTimeoutThreadの一種で、指定された時間の操作を保持して実行します。

setTimeout(function,time_in_mills);

ここでは、最初の引数は関数型である必要があります。3秒後に名前を出力する場合の例として、コードは以下のようになります。

setTimeout(function(){console.log('your name')},3000);

覚えておくべき重要な点は、setTimeoutメソッドを使用して何をしたいのか、それを行う関数内。いくつかのパラメーターを解析して他のメソッドを呼び出したい場合、コードは次のようになります。

setTimeout(function(){yourOtherMethod(parameter);},3000);

ハッピーnodejsコーディング:)

6
Ashana.Jackol

setTimeout(callback,t)はコールバックの実行に使用されます少なくともtミリ秒後。実際の遅延は、OSタイマーの粒度やシステム負荷などの多くの外部要因に依存します。

そのため、設定された時間の少し後に呼び出される可能性がありますが、以前に呼び出されることはありません。

タイマーは24.8日を超えることはできません。

5
Siva Prakash