Why does node.js handle setTimeout(func, 1.0) incorrectly?

怎甘沉沦 提交于 2019-12-18 15:35:25

问题


While working on a timing sensitive project, I used the code below to test the granularity of timing events available, first on my desktop machine in Firefox, then as node.js code on my Linux server. The Firefox run produced predictable results, averaging 200 fps on a 1ms timeout and indicating I had timing events with 5ms granularity.

Now I know that if I used a timeout value of 0, the Chrome V8 engine Node.js is built on would not actually delegate the timeout to an event but process it immediately. As expected, the numbers averaged 60,000 fps, clearly processing constantly at CPU capacity (and verified with top). But with a 1ms timeout the numbers were still around 3.5-4 thousand cycle()'s per second, meaning Node.js cannot possibly be respecting the 1ms timeout which would create a theoretical maximum of 1 thousand cycle()'s per second.

Playing with a range of numbers, I get:

  • 2ms: ~100 fps (true timeout, indicating 10ms granularity of timing events on Linux)
  • 1.5: same
  • 1.0001: same
  • 1.0: 3,500 - 4,500 fps
  • 0.99: 2,800 - 3,600 fps
  • 0.5: 1,100 - 2,800 fps
  • 0.0001: 1,800 - 3,300 fps
  • 0.0: ~60,000 fps

The behavior of setTimeout(func, 0) seems excusable, because the ECMAScript specification presumably makes no promise of setTimout delegating the call to an actual OS-level interrupt. But the result for anything 0 < x <= 1.0 is clearly ridiculous. I gave an explicit amount of time to delay, and the theoretical minimum time for n calls on x delay should be (n-1)*x. What the heck is V8/Node.js doing?

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();

回答1:


For completeness I would like to point out to the nodeJS implementation:

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

Which is:

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

Remember this statement:

IDLE TIMEOUTS

Because often many sockets will have the same idle timeout we will not use one timeout watcher per item. It is too much overhead.
Instead we'll use a single watcher for all sockets with the same timeout value and a linked list.

This technique is described in the libev manual: http://pod.tst.eu/http://cvs.schmorp.de/libev/ev.pod#Be_smart_about_timeouts

And we pass the same timeout value (1) here.

The implementation for Timer is here:
https://github.com/nodejs/node-v0.x-archive/blob/master/src/timer_wrap.cc




回答2:


From the node.js api docs for setTimeout(cb, ms) (emphasis mine):

It is important to note that your callback will probably not be called in exactly delay milliseconds - Node.js makes no guarantees about the exact timing of when the callback will fire, nor of the ordering things will fire in. The callback will be called as close as possible to the time specified.

I suppose that "as close as possible" means something different to the implementation team than to you.

[Edit] Incidentally, it appears that the setTimeout() function isn't mandated by any specification (although apparently part of the HTML5 draft). Moreover, there appears to be a 4-10ms de-facto minimum level of granularity, so this appears to be "just how it is".

The great thing about open source software is that you can contribute a patch to include a higher resolution per your needs!



来源:https://stackoverflow.com/questions/9288050/why-does-node-js-handle-settimeoutfunc-1-0-incorrectly

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!