我对node.js文档的以下段落感到困惑。
...执行计时器的顺序将根据称为上下文而变化。如果两者都是从主模块中调用的,那么时间将受过程的性能(可能会受到机器上运行的其他应用程序的影响)。
)。
例如,如果我们运行以下脚本,该脚本不在I/O周期内(即主模块),则执行两个计时器的顺序是非确定性的,因为它受到它的性能。该过程:
它继续显示以下示例,
// timeout_vs_immediate.js
setTimeout(() => {
console.log('timeout');
}, 0);
setImmediate(() => {
console.log('immediate');
});
$ node timeout_vs_immediate.js
timeout
immediate
$ node timeout_vs_immediate.js
immediate
timeout
我不明白是什么使结果非确定性。由于计时器
阶段发生在检查
阶段之前,因此不应在 settimeout
安排的回调在由 setimmediate <计划
之前始终执行。 /代码>?我认为事件循环中的阶段顺序不会因上下文开关而改变。
该文件还指出
但是,如果您在I/O周期内将两个呼叫移动,则立即回调始终首先执行:
好的,但是什么使所谓的“ I/O周期”与主模块不同?
我知道有很多相关的问题,但是所有答案都仅通过引用文档来说明这一事实,而没有解释非确定性的发挥作用,所以我认为这不是重复的。
I am confused by the following paragraph of the Node.js documentation.
... The order in which the timers are executed will vary depending on the context in which they are called. If both are called from within the main module, then timing will be bound by the performance of the process (which can be impacted by other applications running on the machine).
For example, if we run the following script which is not within an I/O cycle (i.e. the main module), the order in which the two timers are executed is non-deterministic, as it is bound by the performance of the process:
It proceeds to show the following example
// timeout_vs_immediate.js
setTimeout(() => {
console.log('timeout');
}, 0);
setImmediate(() => {
console.log('immediate');
});
$ node timeout_vs_immediate.js
timeout
immediate
$ node timeout_vs_immediate.js
immediate
timeout
I don't understand what makes the result non-deterministic. Since the timers
phase happens before the check
phase, shouldn't the callbacks scheduled by setTimeout
always execute before those scheduled by setImmediate
? I don't think the order of the phases in the event loop would change due to a context switch or something.
The document also states that
However, if you move the two calls within an I/O cycle, the immediate callback is always executed first:
OK, but what makes so-called "I/O cycles" different from the main module?
I know there are a lot of related questions, but all answers merely state this fact by citing the documentation, without explaining where the non-determinism comes into play, so I don't think this is a duplicate.
发布评论
评论(2)
实际的窍门在 settimeout ,它将时间增加到1到1以下。因此
settimeout(fn,0)
实际上等于settimeout(fn,1)
。另一个有趣的观察结果是,在setimmeadepeare之后,多个计时器也可能在和之前运行:
这是因为
settimeout
呼叫getlibuvnow
内部,它将调用envy> envy> enk - &gt; getNow()
,它不仅可以获得Libuv的当前时间,而且还可以href =“ https://github.com/nodejs/node/node/blob/5fad0b93667ffc6e4def529996b95299b26319/src/env.cc#l945因此,可能会在不同的到期时间将计时器放入计时器队列中,因此计时器阶段只会接收其中一些。主模块在初始化libuv之前运行,而大多数其他代码将在 poll 阶段运行, design.html“ rel =“ noreferrer”> libuv loop 。因此,主模块初始化之后是计时器阶段,而轮询阶段之后是“检查手柄”阶段,其中包括
setimMediate
回调。因此,通常在主模块中,计时器将在立即立即运行(如果到期),如果安排在回调中,则立即在计时器之前运行。The actual trick is in the Timeout constructor which is called by
setTimeout
and which increases times below 1 to 1. ThussetTimeout(fn, 0)
is actually equivalent tosetTimeout(fn, 1)
.When libuv initializes, it starts with timers after updating its internal clock, and when one millisecond already passed till then it's gonna pick up the timer before proceeding to the poll phase (which is followed by the setImmediate phase).
Another interesting observation is that multiple timers might also run before and after setImmeadiate:
That's because
setTimeout
callsgetLibuvNow
internally, which will callenv->GetNow()
and which not only gets the current time of libuv, but also updates it. Thus it might happen that the timer get put into the timer queue with different due times, and thus the timer phase will only pick up some of them.The main module gets run before libuv is initialized, whereas most other code will run in the poll phase of the libuv loop. Thus the main module initialization is followed by the timer phase, whereas the poll phase is followed by the 'check handles' phase, which among others runs the
setImmediate
callbacks. Thus usually in the main module timers would run before immediates (if they're due) and if scheduled in callbacks, immediates would run before timers.我也会为可见性写一个Aswer,因为这是一个很好的问题,节点文档确实具有误导性,我也必须挖掘一些资源……
这个问题回答了 here (接受的答案)很好性能基准测试。
但是,可以在另一个答案中找到实际的解释,该答案指向本文更好地解释了事件循环。
另外,阅读这个答案并解释了哪个部分取决于平台和耗时CPU并产生非确定性,以及0已转换为0的事实在settimeout上内部为1),以提出在nodejs上提出的问题,提出了同样的问题,似乎可以进一步解释它。
I'll write an aswer as well for visibility, since it's a good question and node documentation indeed is misleading and I had to dig a bit to find some resources as well...
This question was answered here (accepted answer) very well with a performance benchmark testing..
But the actual explaination can be found in another answer that points to this article which explains the event loop better.
Also, read this answer (this one is the best one, it goes through the internal code and explains which section is platform dependant and time consuming of the CPU and generates the non-determinism and also the fact that 0 is transformed into 1 internally for setTimeout) to an issue raised on nodejs asking the same question which seems to explain it even further.