对于即将要使用node.js的项目,我需要在定期时间内执行各种日常维护任务。具体来说,有些任务每毫秒执行一次,有些任务每20毫秒执行一次(每秒50次),还有些任务每秒执行一次。所以我考虑使用setInterval(),但结果很有趣:许多函数调用被跳过了。
我使用的基准测试如下:
更好了,但每秒大约会跳过一个函数调用。而对于20毫秒:
在这种情况下,它跳过了很少的调用(33秒后间隔增加到2,108秒后增加到3)。
数字有所变化,但在运行之间惊人地保持一致:连续三次运行第一个1毫秒基准测试,在10秒后产生了延迟9267、9259和9253。
我没有找到关于这个特定问题的参考资料。有这个经常引用的Ressig文章和许多相关的JavaScript问题,但大多数假设代码在浏览器中运行而不是在node.js中。
真正的问题是:可以更好地完成吗,无论是使用setInterval()还是node.js内的其他计时器?提前感谢。
我使用的基准测试如下:
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);
有一个长为1秒的计时器和一个可以使用变量short
调整的短计时器,此处为1毫秒。每秒钟我们打印出短周期中预期的滴答数与实际更新短计时器次数之间的差异。
当短计时器为1毫秒时,它的行为如下:
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
更好了,但每秒大约会跳过一个函数调用。而对于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毫秒基准测试,在10秒后产生了延迟9267、9259和9253。
我没有找到关于这个特定问题的参考资料。有这个经常引用的Ressig文章和许多相关的JavaScript问题,但大多数假设代码在浏览器中运行而不是在node.js中。
现在来到了令人恐惧的问题:这里发生了什么?开个玩笑;显然是函数调用被跳过了。但我看不出规律。我认为长周期可能会阻止短周期,但在1毫秒的情况下没有任何意义。短周期函数调用不会重叠,因为它们只更新一个变量,并且即使有1毫秒的短周期,node.js进程也接近5%的CPU。负载平均值很高,约为0.50。但我不知道为什么一千次调用会如此拖累我的系统,因为node.js可以完美地处理更多的客户端;这必须是setInterval()非常消耗CPU(或者我做错了什么)。
一个显而易见的解决方案是使用更长的计时器对函数调用进行分组,然后多次运行短周期函数调用以模拟较短的计时器。然后使用长周期作为“扫帚车”,在较低间隔中漏掉任何调用。例如:设置20毫秒和1000毫秒setInterval()调用。对于1毫秒的调用:在20毫秒回调中调用它们20次。对于1000毫秒的调用:检查20毫秒函数调用了多少次(例如47),执行任何剩余的调用(例如3)。但这个方案可能会有点复杂,因为调用可能会以有趣的方式重叠;尽管它看起来可能不规则。真正的问题是:可以更好地完成吗,无论是使用setInterval()还是node.js内的其他计时器?提前感谢。