【问题标题】:Odd behavior with setInterval() in node.js (windows only, works in linux)node.js 中 setInterval() 的奇怪行为(仅限 Windows,适用于 linux)
【发布时间】:2020-12-07 07:08:21
【问题描述】:

我在使用 windows 机器时遇到了一些奇怪的 node.js 问题,而这在 linux 机器上不会发生。

在低延迟设置(

//should be time in MS between executions
var delay = 10;

//how many seconds to run the test
var testPeriods = 10;

var counter = 0;
var startTime = new Date().getTime();

var interval = setInterval(() => {
    ++counter;
    if (new Date().getTime() >= startTime+1000*testPeriods) {
        console.log('Mean Function Calls per Second:', counter/testPeriods);
        clearInterval(interval);
    }
}, delay);

一些测试数据,来自我的双启动linux和windows的电脑:

Delay (ms) | Expected | Linux result | Windows result
-----------+----------+--------------+---------------
       100 |       10 |         10.0 |            9.2
        50 |       20 |         20.0 |           16.0
        25 |       40 |         39.8 |           32.0
        10 |      100 |         98.4 |           63.8

您会注意到,在较低的延迟设置之前,linux 结果几乎完美匹配,即使它们也相差不远。另一方面,windows 结果远远不够。

我认为与 linux 版本相比,node 的 windows 版本的优化可能很差。所以起初,我假设我提供的函数执行时间太长,从而延迟了下一次执行。然而,情况似乎并非如此。毕竟,如果我假设提供的函数无论如何都需要类似的时间来执行,那么我知道 Windows 机器可以在最低延迟设置下每秒最多执行约 63 次。那么为什么它在应该执行约 40 次(延迟 @ 25 毫秒)时只执行约 32 次?

如果有人能给我一些关于为什么会发生这种情况或我做错了什么的见解,那将不胜感激。

编辑:根据@jfriend00 的建议简化代码,并更新测试结果以匹配。

【问题讨论】:

  • 你为什么要做快照?为什么不只检查您是否完成了总经过时间并仅使用您的计数器来计算总经过时间?仅供参考,当我简化并摆脱快照时,我仍然会得到类似的结果,但是代码要简单得多。
  • @jfriend00 是的,那样会更简单。我想我是这样做的,因为这个测试代码直接基于我用于项目的实际代码,需要像这样构造。

标签: javascript node.js linux windows setinterval


【解决方案1】:

一段计划代码的调用速度取决于您的操作系统的定时器中断间隔。根据操作系统,此设置称为 tickjiffy。在某些操作系统上,它是可配置的。

操作系统会定期运行自己的代码来执行检查,例如让进程轮流使用 CPU、清理内存等。为此,操作系统会设置一个计时器中断(实际上它就像 setInterval 仅在硬件级别)以运行自己的代码。

这实际上是操作系统设法运行比可用内核更多的进程/线程的方式,也正是这种机制在操作系统级别驱动 JavaScript 中的 setIntervalsetTimeout。所以基本上线程和setInterval都使用相同的操作系统机制,唯一的区别是线程可以同时使用多个内核,而setInterval只能使用与主js线程相同的内核。

设置tick的频率需要权衡取舍。将 tick 设置得非常短将使您的操作系统更加实时,因为事件处理的延迟大大减少。但是,这也意味着您的操作系统代码使用更高百分比的 CPU 时间,而留给您的应用程序的时间更少。将 tick 设置得更长,将为您的应用提供更多 CPU 时间,从而为您提供更多吞吐量。

我实际上对你的结果有点惊讶。几年前(2000 年代初期),Linux 上的默认 jiffy 设置相当长,因为 Linux 更多地针对服务器使用进行了优化,因此针对吞吐量进行了优化。另一方面,Windows 的 tick 较短,因为 Windows 针对实时任务(例如玩游戏和运行图形应用程序)进行了更多优化。也许这些年来情况发生了变化。

所以,是的,如果您想要跨平台的一致性,那么最少 setInterval 时间可以跨操作系统工作。但是我猜想 10 毫秒就足够了,因为这是我多年来的经验(1 毫秒显然会显示各种操作系统的不同行为)。如果这些天 10 毫秒不起作用,您可以尝试更长的时间间隔,例如 50 毫秒‡ 或 100 毫秒。

‡ 注意:50ms 或 20fps 是无线电控制发射器的更新间隔,因此它是实时的,足以让人类反应驾驶飞机、直升机和无人机而不会坠毁

【讨论】:

  • 嗨!非常感谢您的回答。您的回复让我想到了问题的实际根源,因此我在我常用的浏览器(chrome)而不是 node.js 上尝试了同样的测试。在 linux 和 windows 上,我得到的结果与 linux-platform 节点结果相当或更好。这是否表明问题实际上出在 Windows 平台节点实现本身,而不是操作系统?我知道该节点是基于 chrome js 引擎的一个版本,但我不确定它们有多大不同。
  • 是的。可能。可能有多种问题会导致您的结果。首先,node 在它使用的 V8 版本中总是落后。 Chrome 倾向于使用相当新的版本。所以 V8 中的优化在 Chome 上总是比在 node 上更好。其次,就像我提到的那样,实时和吞吐量之间存在权衡。也许节点开发人员牺牲了响应能力来获得更高的网络吞吐量,如果节点定位在编写服务器上竞争,这是有道理的。第三,从 Safari 到 Firefox 的所有浏览器都获得了巨额投资。可能只是在浏览器上付出了更多的努力
  • 这是有道理的。感谢您的回复,也许我会在 node github repo 上发布一个问题,看看他们有什么要说的。
猜你喜欢
  • 2019-08-26
  • 1970-01-01
  • 2012-09-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多