node.jsを使用した今後のプロジェクトでは、定期的にさまざまなハウスキーピングタスクを実行する必要があります。具体的には、ミリ秒ごとのタスク、20ミリ秒ごと(1秒あたり50回)のタスク、および1秒ごとのタスクがあります。そこで、setInterval()を使用することを考えましたが、面白い結果が得られました。多くの関数呼び出しがスキップされていました。
私が使用したベンチマークは次のとおりです。
var counter = 0;
var seconds = 0;
var short = 1;
setInterval(function() {
counter ++;
}, short);
setInterval(function() {
seconds ++;
log('Seconds: ' + seconds + ', counter: ' +
counter + ', missed ' +
(seconds * 1000 / short - counter));
}, 1000);
short
1秒の長いタイマーと、変数(この場合は1ミリ秒)を使用して調整できる短いタイマーがあります。毎秒、短いサイクルで予想されるティック数と、短いカウンターが更新された実際の回数との差を出力します。
ショートタイマーが1msの場合の動作は次のとおりです。
2012-09-14T23:03:32.780Z Seconds: 1, counter: 869, missed 131
2012-09-14T23:03:33.780Z Seconds: 2, counter: 1803, missed 197
2012-09-14T23:03:34.781Z Seconds: 3, counter: 2736, missed 264
...
2012-09-14T23:03:41.783Z Seconds: 10, counter: 9267, missed 733
多くの関数呼び出しはスキップされます。これは10ミリ秒です:
2012-09-14T23:01:56.363Z Seconds: 1, counter: 93, missed 7
2012-09-14T23:01:57.363Z Seconds: 2, counter: 192, missed 8
2012-09-14T23:01:58.364Z Seconds: 3, counter: 291, missed 9
...
2012-09-14T23:02:05.364Z Seconds: 10, counter: 986, missed 14
より良いですが、おおよそ1秒ごとに1つの関数呼び出しがスキップされます。そして20ミリ秒:
2012-09-14T23:07:18.713Z Seconds: 1, counter: 46, missed 4
2012-09-14T23:07:19.713Z Seconds: 2, counter: 96, missed 4
2012-09-14T23:07:20.712Z Seconds: 3, counter: 146, missed 4
...
2012-09-14T23:07:27.714Z Seconds: 10, counter: 495, missed 5
最後に100ミリ秒:
2012-09-14T23:04:25.804Z Seconds: 1, counter: 9, missed 1
2012-09-14T23:04:26.803Z Seconds: 2, counter: 19, missed 1
2012-09-14T23:04:27.804Z Seconds: 3, counter: 29, missed 1
...
2012-09-14T23:04:34.805Z Seconds: 10, counter: 99, missed 1
この場合、スキップする呼び出しはごくわずかです(ギャップは、33秒後に2に、108秒後に3に増加しました。
数値はさまざまですが、実行間で驚くほど一貫しています。最初の1ミリ秒のベンチマークを3回実行すると、9267、9259、および9253の10秒後に遅延が発生しました。
この特定の問題についての言及は見つかりませんでした。これほど多く引用されているRessigの投稿と、関連するJavaScriptの質問がたくさんありますが、ほとんどの場合、コードはnode.jsではなくブラウザーで実行されると想定しています。
さて、恐ろしい質問です。ここで何が起こっているのでしょうか。ほんの冗談ですよ; 明らかに、関数呼び出しはスキップされています。しかし、私はそのパターンを見ることができません。長いサイクルが短いサイクルを妨げているのではないかと思いましたが、1ミリ秒の場合は意味がありません。短いサイクルの関数呼び出しは、変数を更新するだけなので重複していません。node.jsプロセスは、1ミリ秒の短いサイクルでも5%近くのCPUです。ただし、負荷平均は約0.50と高くなっています。node.jsはさらに多くのクライアントを完全に処理するため、1000回の呼び出しがシステムに大きなストレスを与えている理由はわかりません。setInterval()がCPUを集中的に使用する(または何か間違ったことをしている)ことは事実である必要があります。
明らかな解決策は、より長いタイマーを使用して関数呼び出しをグループ化し、次に短いサイクルの関数呼び出しを何度も実行して、より短いタイマーをシミュレートすることです。次に、長いサイクルを「ほうきワゴン」として使用します。これにより、低い間隔で不在着信が発生します。例:20ミリ秒と1000ミリ秒のsetInterval()呼び出しを設定します。1ミリ秒の呼び出しの場合:20ミリ秒のコールバックで20回呼び出します。1000ミリ秒の呼び出しの場合:20ミリ秒の関数が呼び出された回数(例:47)を確認し、残りの呼び出し(例:3)を実行します。ただし、呼び出しが興味深い方法で重複する可能性があるため、このスキームは少し複雑になります。また、見た目は変わりますが、定期的ではありません。
本当の問題は、setInterval()またはnode.js内の他のタイマーのいずれかを使用して、より適切に実行できるかどうかです。前もって感謝します。