首页 > 解决方案 > node.js 中 setInterval() 的奇怪行为(仅限 Windows,适用于 linux)

问题描述

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

在低延迟设置(< 100 毫秒)下使用 setInterval() 函数时:本质上,所提供的函数被调用的频率比我预期的要少,而且方式非常一致。当使用我在下面快速编写的示例代码时,Windows 机器似乎给出了与 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 结果几乎完美匹配,直到较低的延迟设置,即使它们也不是那么遥远。另一方面,窗口结果远远不够。

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

如果有人可以让我了解为什么会发生这种情况或我做错了什么,那将不胜感激。

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

标签: javascriptnode.jslinuxwindowssetinterval

解决方案


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

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

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

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

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

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

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


推荐阅读