【问题标题】:Why is the behavior of setTimeout(0) and setImmediate() undefined when used in the main module?为什么在主模块中使用时 setTimeout(0) 和 setImmediate() 的行为未定义?
【发布时间】:2018-02-06 15:06:33
【问题描述】:

以下代码取自nodejs event loop documentation

// timeout_vs_immediate.js
setTimeout(() => {
  console.log('timeout');
}, 0);

setImmediate(() => {
  console.log('immediate');
});

根据文档:

例如,如果我们运行以下不在 I/O 中的脚本 循环(即主模块),两个定时器的顺序 执行是不确定的,因为它受性能的约束 过程。

为什么上面的说法是正确的?是不是因为 nodejs 运行时实际上使用了多个线程来挑选必须执行的回调。

我的直觉是:有两个线程为 setTimeoutsetImmediate 执行回调,所以当它们都可用时,这会导致竞争条件,因此输出将是不确定的。

正确吗?还是有任何其他原因导致这是不确定的?

【问题讨论】:

  • 我知道这有点长,但没有比here更好的解释了
  • 好问题!我已经非常仔细地阅读了 node.js 事件循环文档,但没有找到解释。文件似乎只告诉我们它是不确定的,但从未提及原因。
  • @shaochuancs 你认为它的设计是非确定性的吗?
  • @ng.newbie 不,我不认为这是设计使然。我想这种不确定的行为可以通过一些内部 Node.js 机制来解释。很遗憾,没有找到任何文档/文章。

标签: javascript node.js race-condition event-loop


【解决方案1】:

基本上,发生了两件事:

  1. setTimer(0..) 被转换成 setTimer(1..)
  2. 在(下一个)事件循环开始之前,node/libuv 必须执行一个clock_gettime() 从系统获取当前时间。此系统调用所花费的时间是不确定的,因为它取决于当时的系统负载。现在,如果 clock_gettime() 花费超过 1 毫秒,setTimer 回调将运行 (#),否则事件循环继续到下一阶段 (##)。

    • 如果是 (#),setTimeout(0,..) 回调在 setImmediate() 之前运行
    • 如果是 (##),则不是。

参考: https://github.com/nodejs/help/issues/392#issuecomment-305969168

【讨论】:

  • 是的。这应该是答案。
猜你喜欢
  • 1970-01-01
  • 2019-11-13
  • 1970-01-01
  • 2015-02-10
  • 2014-07-29
  • 2020-02-24
  • 2016-11-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多