`setimMediate()`and`settimeout()的时间如何受过程的性能约束?

发布于 2025-02-12 11:12:15 字数 1153 浏览 0 评论 0 原文

我对node.js文档的以下段落感到困惑。

vs settimeout()

...执行计时器的顺序将根据称为上下文而变化。如果两者都是从主模块中调用的,那么时间将受过程的性能(可能会受到机器上运行的其他应用程序的影响)。

)。

例如,如果我们运行以下脚本,该脚本不在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.

setImmediate() vs setTimeout()

... 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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

无声静候 2025-02-19 11:12:15

实际的窍门在 settimeout ,它将时间增加到1到1以下。因此 settimeout(fn,0)实际上等于 settimeout(fn,1)


另一个有趣的观察结果是,在setimmeadepeare之后,多个计时器也可能在之前运行:

setTimeout(() => console.log('timer'), 1);
setTimeout(() => console.log('timer'), 1);
setImmediate(() => console.log('immediate'));
// can produce:
// timer
// immediate
// timer

这是因为 settimeout 呼叫 getlibuvnow 内部,它将调用 envy> envy> enk - &gt; getNow(),它不仅可以获得Libuv的当前时间,而且还可以href =“ https://github.com/nodejs/node/node/blob/5fad0b93667ffc6e4def529996b95299b26319/src/env.cc#l945因此,可能会在不同的到期时间将计时器放入计时器队列中,因此计时器阶段只会接收其中一些。

好的,但是是什么使所谓的“ I/O周期”与主模块不同?

主模块在初始化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. Thus setTimeout(fn, 0) is actually equivalent to setTimeout(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:

setTimeout(() => console.log('timer'), 1);
setTimeout(() => console.log('timer'), 1);
setImmediate(() => console.log('immediate'));
// can produce:
// timer
// immediate
// timer

That's because setTimeout calls getLibuvNow internally, which will call env->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.

OK, but what makes so-called "I/O cycles" different from the main module?

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.

你的往事 2025-02-19 11:12:15

我也会为可见性写一个Aswer,因为这是一个很好的问题,节点文档确实具有误导性,我也必须挖掘一些资源……

这个问题回答了 here (接受的答案)很好性能基准测试。

但是,可以在另一个答案中找到实际的解释,该答案指向本文更好地解释了事件循环。

另外,阅读这个答案并解释了哪个部分取决于平台和耗时CPU并产生非确定性,以及0已转换为0的事实在settimeout上内部为1),以提出在nodejs上提出的问题,提出了同样的问题,似乎可以进一步解释它。

一个更重要的事情要注意的是,将内部转换为1。

时Settimeout。

这个呼吁UV__hrtime是平台依赖的,并且是CPU时间耗费的工作,因为它使系统制造系统
致电clock_getTime。它受到机器上运行的其他应用程序的影响。

如果第一个循环之前的准备工作花费超过1ms,则计时器阶段调用与之关联的回调。如果小于1ms的事件循环继续下一阶段,并在循环的检查阶段和SettieMout的检查阶段运行setimediate回调。
循环的下一个刻度。

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.

event loop explained

difference explained

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.

One more important things to note is setTimeout when set to 0 is internally converted to 1.

This call to uv__hrtime is platform dependent and is cpu-time-consuming work as it makes system
call to clock_gettime. It's is impacted by other application running on the machine.

If the preparation before the first loop took more than 1ms then the Timer Phase calls the callback associated with it. If it's is less than 1ms Event-loop continues to next phase and runs the setImmediate callback in check phase of the loop and setTimeout in the
next tick of the loop.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文