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


112

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


14
非リアルタイムのオペレーティングシステムでは、重大な正確性を保証することはできません。システム上のあらゆる種類のものがタイマーメカニズムの邪魔になる可能性があります。
先のとがった

回答:


174

setTimeoutのセマンティクスは、Webブラウザーとほぼ同じです。タイムアウト引数は、実行前に待機する最小ミリ秒数であり、保証ではありません。さらに、0、非数値、または負の数値を渡すと、最小ミリ秒待機します。ノードではこれは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. 5000msの間busywait。
  3. イベントループに戻ります。保留中のタイマーを確認して実行します。

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

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

NodeのJavaScript実行はシングルスレッド化されているため、他のほとんどの同時方式よりもはるかに簡単に操作できます。もちろん、トレードオフは、プログラムの不適切な動作をする部分がすべてを無限ループでブロックする可能性があることです。

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


20
非常に正確なconsole.logメッセージの+1を受け取ります。
ファンドモニカの訴訟

文字列でTIMEを大文字にした方法が好きです。とても良い説明!!!
Alisson

43

ノンブロッキングの考え方は、ループの反復が速いということです。したがって、ティックごとに繰り返すには、setTimeoutが妥当な精度(おそらく100ミリ秒程度オフ)まで正確になるまでに十分な時間がかかる必要があります。

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

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

ブラウザまたはノードでこのコードを試してみてください。正確さが保証されていないことがわかります。逆に、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と表示されます...


9

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

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

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

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

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


9

setTimeout一種のThreadであり、一定時間操作を保持して実行します。

setTimeout(function,time_in_mills);

ここでは、最初の引数は関数型でなければなりません。例として、3秒後に名前を印刷する場合、コードは次のようになります。

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

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

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

8

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

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

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.