【问题标题】:is Multiple setTimeout execution single threaded or mutli threaded in Node.js?Node.js 中的多个 setTimeout 执行是单线程还是多线程?
【发布时间】:2021-04-15 12:46:37
【问题描述】:

假设我有 3 个 setTimeouts,如下所示:

console.log(new Date().toLocaleTimeString());

setTimeout(() => { console.log(new Date().toLocaleTimeString()); }, 3000);

setTimeout(() => { console.log(new Date().toLocaleTimeString()); }, 6000);

setTimeout(() => { console.log(new Date().toLocaleTimeString()); }, 9000);

由于 Node 是单线程的,每个超时的执行应该一个接一个。因此,输出应如下所示:

9 am 0s (intial)

9 am 3s(+3s)

9 am 9s(+6s)

9 am 18s(+9s)

但我发现的是:

9 am 0s (initial)

9 am 3s(+3s)

9 am 6s(+3s)

9 am 9s(+3s)

所以很明显,所有超时都是同时开始的。每个超时之间的差异被添加到每个超时之间,在这种情况下是 +3s,

在这种情况下,这会使 nodejs 成为多线程吗?我确实知道并非节点的所有部分都在同一个线程中运行,并且很少会在同一个线程之外执行。

有人可以在这方面给我一个更好的感觉吗?或者也许我的方法是错误的。

【问题讨论】:

  • JS 是基于事件的。其他代码可以在超时未决时运行(它是异步的)
  • setTimeout() 调用在很短的时间内一个接一个地运行。第一次调用的延迟值对第二次调用的延迟没有影响(嗯,影响很小)。
  • @blex 我知道需要 node api 的函数确实是异步执行的,我是在 node api 内询问执行 ..
  • @ViswanadhDeepak 不是全部。但通常需要回调的函数(forEachmap 等除外)
  • @Pointy 是的,我确实注意到 setTimeout() 调用是在非常微小的时间差异上进行的......如果我们考虑缩放到秒,那么这些调用是同时进行的......

标签: javascript node.js multithreading settimeout


【解决方案1】:

由于Node是单线程的,每次超时的执行应该是一个接一个。

Node.js 不是单线程的。但默认情况下它确实运行单个 JavaScript 线程。您可以通过worker_threads module 运行其他人。 (每个工人都有自己的 JavaScript 环境;他们可以交流。)

因此输出应如下所示:

不,不应该。您的代码一个接一个启动了三个计时器。对setTimeout 的所有三个调用都会立即运行,并启动它们的计时器。然后事件循环继续,等待做某事,大约三秒钟后,它看到第一个计时器回调的时间到了,所以它运行那个回调。然后事件循环继续。在那之后大约三秒钟(总共六秒钟),它看到是第二次回调的时候了,然后就这样做了。循环继续……三秒钟后,它执行第三次回调。这一切都在一个线程上。

关于 Node.js here 中的事件循环的更多信息。

Node 的事件循环类似于浏览器的。这是您在浏览器中的示例,带有一些额外的日志记录:

const start = Date.now();

function elapsedPrefix() {
    return ("+" + (Date.now() - start)).padStart(4, " ");
}

function log(...msgs) {
    console.log(`${elapsedPrefix()}: ${msgs.join(" ")}`);
}

function now() {
    return new Date().toISOString().substring(11, 12);
}

function startTimeout(num, fn, ms) {
    log(`Start timer ${num} for ${ms}ms`);
    setTimeout(() => {
        log(`Timer ${num} firing`);
        fn();
    }, ms);
}

log(`Starting timers`);

startTimeout(1, () => { log(new Date().toLocaleTimeString()); }, 3000);
startTimeout(2, () => { log(new Date().toLocaleTimeString()); }, 6000);
startTimeout(3, () => { log(new Date().toLocaleTimeString()); }, 9000);

log(`Timers started`);

【讨论】:

  • @Crowder,我的意思是说它默认在单线程上运行。是的,我的问题是这些计时器会同时启动吗?如果他们这样做了......他们会在同一个线程上吗?只是试图区分节点的哪些部分进行多线程处理(如果有)
  • @ViswanadhDeepak - 除非您使用 worker_threads 模块,否则您的 所有 JavaScript 代码将在单个线程上运行。 Node.js 在该线程上使用带有事件循环的异步 I/O,处理待处理的 JavaScript 作业队列(如运行回调)。异步 I/O 意味着 I/O 操作可以在不拖延的情况下完成。我认为 Node.js 可能有几个它在内部使用的其他实用程序线程,但这些线程不会暴露给您的代码。您的代码始终在单个线程中运行(除非您告诉它不要这样做)。 :-)
  • @Crowder Node 使用 v8 java 脚本引擎,它在内部主要是单线程的,对吗?这是否使 nodejs 部分成为单线程?
  • @ViswanadhDeepak - 据我所知,这更像是 Node.js 团队的设计决定,尤其是因为 JavaScript 直到最近才具有线程的任何概念,并且唯一重要的现实 -它的世界实现只允许每个我们现在称为 realm(基本上是 JavaScript 全局环境)的单个线程。
猜你喜欢
  • 2014-10-12
  • 1970-01-01
  • 2021-02-20
  • 2018-08-16
  • 2021-12-06
  • 2011-11-22
  • 2010-09-09
  • 1970-01-01
  • 2011-09-29
相关资源
最近更新 更多