为什么 node.js 处理 setTimeout(func, 1.0) 不正确? [英] Why does node.js handle setTimeout(func, 1.0) incorrectly?

查看:20
本文介绍了为什么 node.js 处理 setTimeout(func, 1.0) 不正确?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在处理时间敏感项目时,我使用下面的代码来测试可用时间事件的粒度,首先是在我的台式机上的 Firefox,然后是我的 Linux 服务器上的 node.js 代码.Firefox 运行产生了可预测的结果,在 1 毫秒超时时平均 200 fps,并表明我有 5 毫秒粒度的计时事件.

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.

现在我知道,如果我使用的超时值为 0,则基于 Node.js 的 Chrome V8 引擎实际上不会将超时委托给事件,而是立即处理它.正如预期的那样,这些数字平均为 60,000 fps,显然在 CPU 容量下不断处理(并通过 top 验证).但是在 1ms 超时的情况下,数字仍然约为每秒 3.5-4 千次循环(),这意味着 Node.js 不可能遵守 1 毫秒超时,这将创建每秒 1000 次循环()的理论最大值.

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(真正的超时,表示 Linux 上的计时事件粒度为 10 毫秒)
  • 1.5:相同
  • 1.0001:相同
  • 1.0:3,500 - 4,500 帧/秒
  • 0.99:2,800 - 3,600 帧/秒
  • 0.5:1,100 - 2,800 帧/秒
  • 0.0001:1,800 - 3,300 帧/秒
  • 0.0:约 60,000 帧/秒

setTimeout(func, 0) 的行为似乎是可以原谅的,因为 ECMAScript 规范大概没有承诺 setTimout 将调用委托给实际的操作系统级中断.但是任何 0 < 的结果x <= 1.0 显然是荒谬的.我给出了明确的延迟时间,n 个调用 x 延迟的理论最小时间应该是 (n-1)*x.V8/Node.js 到底在做什么?

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

推荐答案

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

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

是:

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

记住这句话:

空闲超时

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

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.

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

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

我们在这里传递相同的超时值(1).

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

这篇关于为什么 node.js 处理 setTimeout(func, 1.0) 不正确?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆