为什么node.js不正确地处理setTimeout(func,1.0)?

为什么node.js不正确地处理setTimeout(func,1.0)?,node.js,v8,Node.js,V8,在处理一个对时间敏感的项目时,我使用下面的代码来测试可用时间事件的粒度,首先是在Firefox中的桌面计算机上,然后是Linux服务器上的node.js代码。Firefox的运行产生了可预测的结果,在1毫秒的超时时间内平均每秒200帧,这表明我有5毫秒粒度的定时事件 现在我知道,如果我使用的超时值为0,那么构建的Chrome V8 engine Node.js实际上不会将超时委托给事件,而是立即处理它。正如预期的那样,这些数字平均为60000 fps,显然是以CPU容量持续处理(并通过top验证

在处理一个对时间敏感的项目时,我使用下面的代码来测试可用时间事件的粒度,首先是在Firefox中的桌面计算机上,然后是Linux服务器上的node.js代码。Firefox的运行产生了可预测的结果,在1毫秒的超时时间内平均每秒200帧,这表明我有5毫秒粒度的定时事件

现在我知道,如果我使用的超时值为0,那么构建的Chrome V8 engine Node.js实际上不会将超时委托给事件,而是立即处理它。正如预期的那样,这些数字平均为60000 fps,显然是以CPU容量持续处理(并通过top验证)。但在1ms超时的情况下,数字仍然在每秒3.5-4千个cycle(),这意味着Node.js不可能遵守1ms超时,这将产生每秒1000个cycle()的理论最大值

使用一系列数字,我得到:

  • 2ms:~100fps(真超时,表示Linux上计时事件的10ms粒度)
  • 1.5:相同
  • 1.0001:相同
  • 1.0:3500-4500 fps
  • 0.99:2800-3600 fps
  • 0.5:1100-2800 fps
  • 0.0001:1800-3300 fps
  • 0.0:~60000 fps
setTimeout(func,0)的行为似乎是可以原谅的,因为ECMAScript规范可能没有承诺setTimeout将调用委托给实际的OS级中断。但任何0 需要注意的是,您的回调可能不会在精确的延迟毫秒内被调用-Node.js不保证回调何时启动的确切时间,也不保证调用的顺序。将在尽可能接近指定时间的情况下调用回调

我认为“尽可能接近”对实现团队的意义与对您的意义不同

[Edit]顺便说一句,任何规范似乎都没有强制要求(尽管如此)。此外,事实上有一个4-10毫秒的最小粒度级别,所以这似乎是“实际情况”


开源软件的伟大之处在于,您可以根据自己的需要提供一个包含更高分辨率的补丁

为了完整起见,我想向nodeJS实现指出:

即:

// Timeout values > TIMEOUT_MAX are set to 1.
var TIMEOUT_MAX = 2147483647; // 2^31-1
...
exports.setTimeout = function(callback, after) {
    var timer;

    after *= 1; // coalesce to number or NaN

    if (!(after >= 1 && after <= TIMEOUT_MAX)) {
        after = 1; // schedule on next tick, follows browser behaviour
    }

    timer = new Timeout(after);
    ...
}
//超时值>超时最大值设置为1。
变量超时_MAX=2147483647;//2^31-1
...
exports.setTimeout=函数(回调,之后){
无功定时器;
*=1之后;//合并为数字或NaN

如果(!(after>=1&&after@HonoredMule:这些数字“毫无意义”由于您的期望或由于他们如何实现软件的具体情况?顺便说一句,setInterval仅在node.js中的间隔>=1.0时运行,并且似乎总是在任何地方使用真正的中断,在Linux上显示5毫秒的粒度,在Firefox上显示4毫秒的粒度。“不保证”当我们受操作系统级中断粒度的支配时,这是意料之中的事情,但这不会每秒产生4000次中断。我想从API级别(即0=>立即调用,直接到节点的事件队列,>1.0=>真正的中断)来解释/Node.js正在做什么。文档什么也没说。对不起,我从来没有打算按原样发布第一条评论(想打断一段)--我在编辑时间用完后删除了它。无论如何,没有更详细的文档,我的期望很难设定……因此问题就来了。@HonoredMule:所以我认为答案是你要求的太多了!=)node.js的家伙们已经清楚地表明了他们认为什么是可以接受的;它没有表现出你想要的样子的原因是由于在实现上的成本/收益权衡。OSS的伟大之处在于,如果你想要一个特定的功能或行为,你可以创建自己的补丁。我想如果编写软件的人真的告诉你,那就太好了告诉我们它的功能,这样我们就知道应该从哪里获取。但我不应该攻击你的答案……我选择了一个糟糕的问题标题。“V8/Node.js在这里做什么”(Node.js如何实现setTimeout)这是我真正的问题——我不是C开发人员,希望得到一个文档级的答案。/我猜Node.js团队在野外观察到的代码使用
1
作为超时值表示“尽快”。我知道很多程序员(包括我自己)在编写
setTimeout时犹豫不决(someFunc,0)
因为
0
在这里感觉有点“不对劲”…零的超时不是超时。
1
似乎是这种代码中表示尽快的下一个逻辑值。因此Node.js代码可能只是有一个类似
if(timeout>1){scheduleTimeout(someFunc,timeout);}或者{scheduleNextTick(someFunc);}的检查
非常有趣的问题。顺便说一句,我喜欢这种研究!回顾过去,我倾向于推测0// Timeout values > TIMEOUT_MAX are set to 1. var TIMEOUT_MAX = 2147483647; // 2^31-1 ... exports.setTimeout = function(callback, after) { var timer; after *= 1; // coalesce to number or NaN if (!(after >= 1 && after <= TIMEOUT_MAX)) { after = 1; // schedule on next tick, follows browser behaviour } timer = new Timeout(after); ... }