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

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

现在我知道,如果我使用的超时值为0,那么Chrome V8引擎Node.js将不会实际上将超时委派给事件,而是立即处理它。 正如预期的那样,这些数字平均为60,000 fps,在CPU容量上不断处理(并通过顶层validation)。 但是在1ms的超时时间内,数字仍然是每秒3.5-4000个周期,这意味着Node.js不可能考虑到1ms的超时时间,这会造成理论最大值每秒1000个周期。

玩一系列的数字,我得到:

  • 2ms:〜100 fps(真正的超时,表示在Linux上10ms的定时事件粒度)
  • 1.5:相同
  • 1.0001:一样
  • 1.0:3,500 – 4,500 fps
  • 0.99:2,800 – 3,600 fps
  • 0.5:1,100 – 2,800fps
  • 0.0001:1,800-3,300fps
  • 0.0:〜60,000 fps

setTimeout(func,0)的行为似乎是可以理解的,因为ECMAScript规范可能不会承诺setTimout将调用委托给实际的OS级中断。 但是任何0 <x <= 1.0的结果显然是荒谬的。 我给了一个明确的延迟时间,n个呼叫在x时延上的理论最短时间应该是(n-1)* x。 V8 / Node.js在干什么?

var timer, counter = 0, time = new Date().getTime(); function cycle() { counter++; var curT = new Date().getTime(); if(curT - time > 1000) { console.log(counter+" fps"); time += 1000; counter = 0; } timer = setTimeout(cycle, 1); } function stop() { clearTimeout(timer); } setTimeout(stop, 10000); cycle(); 

       

网上收集的解决方案 "为什么node.js不正确地处理setTimeout(func,1.0)?"

为了完整性,我想指出nodeJS的实现:

https://github.com/nodejs/node-v0.x-archive/blob/master/lib/timers.js#L214

这是:

 // 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); ... } 

记住这个说法:

怠速时间

因为经常有许多套接字将有相同的空闲超时,我们不会使用每个项目的超时观察者。 这是太多的开销。
相反,我们将使用具有相同超时值的所有套接字的单个观察器和一个链表。

这个技术在libev手册中有描述: http ://pod.tst.eu/http: //cvs.schmorp.de/libev/ev.pod#Be_smart_about_timeouts

我们在这里传递same timeout value (1)

Timer的实现在这里:
https://github.com/nodejs/node-v0.x-archive/blob/master/src/timer_wrap.cc

从node.js api docs for setTimeout(cb, ms) (重点是我的):

重要的是要注意,你的callback可能不会被精确地延迟几毫秒 – Node.js 不能保证什么时候callback将会触发的确切时间 ,也不会触发sorting的东西。callback将被称为尽可能接近指定的时间。

我认为“尽可能接近”是指与实施团队不同的东西,而不是你。

顺便说一下,看起来setTimeout()函数不是任何规范要求的(尽pipe显然是HTML5草案的一部分 )。 此外,似乎有一个4-10毫秒事实上的最小粒度水平,所以这似乎是“它是如何”。

关于开源软件的好处是你可以提供一个补丁来包含更高分辨率的你的需求!