128

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

4

5 に答える 5

187

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. タイムアウトを 100 ミリ秒にスケジュールします。
  2. ビジー状態で 5000ms 待ちます。
  3. イベントループに戻ります。保留中のタイマーをチェックして実行します。

そうでない場合は、JavaScript の一部を別の部分に「割り込ませる」ことができます。このようなコードが推論するのが非常に難しくならないようにするには、ミューテックスやセマフォなどを設定する必要があります。

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

Node の JavaScript 実行のシングルスレッド性により、他のほとんどのスタイルの同時実行よりも操作がはるかに簡単になります。もちろん、トレードオフは、プログラムの不適切な部分が無限ループで全体をブロックする可能性があることです。

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

于 2012-05-26T16:06:09.847 に答える
45

非ブロッキングの考え方は、ループの反復が速いということです。したがって、ティックごとに反復するのに十分な時間がかかるため、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が表示されます...

于 2011-05-01T15:05:04.480 に答える
9

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

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

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

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

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

于 2011-05-01T16:19:05.263 に答える