【问题标题】:libuv threads are executing sequentially in nodejslibuv线程在nodejs中按顺序执行
【发布时间】:2020-02-27 08:29:52
【问题描述】:

所以我正在执行这段代码来检查 libuv 库创建的线程池中的线程数 -

var fs = require('fs');
var util = require('util');
var sleep = require('sleep');
var start = process.hrtime();

var sample_func = function(callback) {
  var i = 0;
  sleep.sleep(1);
  callback();
}
for (var i = 0; i < 6; ++i) {
  (function (id) {
    sample_func(function () {
      var end = process.hrtime(start);
      console.log(util.format('sample func %d finished in %ds', id, end[0] + end[1] / 1e9));
    });
  })(i);
}

由于 libuv 默认在线程池中创建 4 个线程,并且我的示例函数是异步的,因此我希望在我的控制台中打印此输出 -

sample func 0 finished in 1.003170344s
sample func 1 finished in 1.052704191s
sample func 2 finished in 1.058100525s
sample func 3 finished in 1.060514229s
sample func 4 finished in 2.003446385s
sample func 5 finished in 2.007682862s

所以前 4 次迭代并行运行,最后 2 次必须等待前 4 次完成。然而我得到的是这个 -

sample func 0 finished in 1.00095422s
sample func 1 finished in 2.056155718s
sample func 2 finished in 3.058480649s
sample func 3 finished in 4.061336076s
sample func 4 finished in 5.063556904s
sample func 5 finished in 6.066219487s

这意味着每次迭代都会一个接一个地执行,总共需要 6 秒。任何人都可以在这里帮助我为什么会发生这种情况?

PS:我打印了 process.env.UV_THREADPOOL_SIZE 值,我得到了 undefined;节点版本:v12.9.1

谢谢

【问题讨论】:

  • sleep 在每次迭代中同步阻塞一秒钟。不确定 libuv,您将不得不以其他方式调用并行处理(child_process?)
  • Node.js 只使用一个线程来执行代码。它对网络 I/O 使用相同的单线程(不是单独的线程)。它只旋转额外的线程来处理磁盘 I/O、DNS(通常没有非阻塞 API)和一些加密函数(因为它是计算,而不是 I/O)。浏览器中的 Node.js 和 javascript 本质上是单线程的。它是异步/事件/非阻塞的,但是是单线程的(你会发现在其他语言中非阻塞代码往往是单线程的)。它可以并行等待,但可以串行执行计算
  • 据我了解,所有的异步函数都由线程池中的线程执行,然后回调进入任务队列,被事件循环一一拾取在main中执行线。如果我错了,请纠正我。

标签: node.js asynchronous libuv


【解决方案1】:

Nodejs 事件循环(由 Libuv 实现)在单线程(主线程)中运行。阻塞代码(在你的情况下是 sleep())在主线程中运行。网络、文件和 DNS IO 操作由 Libuv 异步运行。 Nodejs 使用以下方案:

Node.js 尽可能使用异步系统 API,但是 在它们不存在的地方,使用 libuv 的线程池来创建 基于同步系统 API 的异步节点 API。 Node.js API 使用线程池的有:

  • 所有 fs API,文件观察程序 API 和以下 API 除外:
  • 显式同步异步加密 API,例如 crypto.pbkdf2()、crypto.scrypt()、crypto.randomBytes()、 crypto.randomFill(), crypto.generateKeyPair()
  • dns.lookup() 所有 zlib *API,明确同步的 API 除外。

现在回到您的问题,sleep.sleep(1); 函数块事件循环(主线程)持续 1 秒,正如 sleep 文档所述。这就是你的函数同步运行的原因。

【讨论】:

    猜你喜欢
    • 2016-05-17
    • 1970-01-01
    • 2015-05-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-27
    • 1970-01-01
    • 2016-04-08
    相关资源
    最近更新 更多