javascript - 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 的建议下简化了代码,并更新了测试结果以匹配。
解决方案
一段预定代码的调用速度取决于您的操作系统的定时器中断间隔。根据操作系统,此设置称为tick或jiffy。在某些操作系统上,它是可配置的。
操作系统会定期运行自己的代码来进行检查,例如让进程轮流使用 CPU、清理内存等。为此,操作系统会设置一个计时器中断(实际上它就像setInterval
在硬件级别一样)来运行自己的代码。
这实际上是操作系统如何设法运行比可用内核更多的进程/线程,并且正是这种机制在操作系统级别驱动setInterval
和setTimeout
在 javascript 中。所以基本上两个线程都setInterval
使用相同的操作系统机制,唯一的区别是线程可以一次使用多个内核,而setInterval
只能使用与主js线程相同的内核。
您设置刻度的频率需要权衡取舍。将刻度设置得很短将使您的操作系统更加实时,因为事件处理的延迟大大减少。但是,这也意味着您的操作系统代码使用更高百分比的 CPU 时间,而留给您的应用程序的时间更少。将刻度设置得更长将为您的应用程序提供更多的 CPU 时间,从而为您提供更多的吞吐量。
我实际上对你的结果有点惊讶。几年前(2000 年代初期),Linux 上的默认jiffy设置相当长,因为 Linux 针对服务器使用进行了更多优化,因此针对吞吐量进行了优化。另一方面,Windows 的时间较短,因为 Windows 针对实时任务(例如玩游戏和运行图形应用程序)进行了更多优化。也许这些年来情况发生了变化。
所以是的,如果您想要跨平台的一致性setInterval
,那么跨操作系统的工作时间最短。但是我猜想 10 毫秒就足够了,因为这是我多年来的经验(1 毫秒显然会显示各种操作系统的不同行为)。如果这些天 10 毫秒不起作用,您可以尝试更长的时间间隔,例如 50 毫秒‡ 或 100 毫秒。
‡ 注意:50ms 或 20fps 是无线电控制发射器的更新间隔,因此它是实时的,足以让人类反应驾驶飞机、直升机和无人机而不会坠毁
推荐阅读
- ios - 如何在ios中reloadData之前获取数据?
- reactjs - 如何在react.js中迭代来自api的json数据
- java - 验证失败时包含参数名称的自定义错误消息
- javascript - 背景颜色的Javascript cookie?
- python - PyV8 - 安装时出错
- python-3.x - 在networkx中导入数据
- javascript - Javascript & Discord.js - 重复数组长度的东西
- mysql - 在 SQL 中使用变量进行转置
- sql-server - 返回 Oracle 数据,字符之间有空格
- wordpress - 将新的 Word Press 迁移到具有旧站点的不同 CPanel 帐户