nodejs同时循环调用异步IO,线程池默认是四个线程,为什么结果不是每四个一组的输出

新手上路,请多包涵

3.png
4.png
请求一次,耗时100ms左右。
1.png
2.png
请求10次,每个耗时1100ms左右。为什么不是第一组四个耗时100ms,第二组四个耗时200ms,最后一组耗时300ms。线程池默认是四个,一次可以处理四个IO请求,然后后面的IO等待线程空闲了再执行。为啥不是这样的呢

阅读 2.4k
3 个回答

你定义的线程池有4个,但实际上线程的执行还受上层进程执行的影响,进程执行又受系统进程管理的影响,这造成线程资源分配不一定是你预想的那么平均、均衡。

谢邀。

这目前不是一条回答,只是罗列了一些可能涉及到的点,背后的原因我晚点查查资料看看能不能找到。

首先,如果我没记错的话,异步的 fs API 会进 thread pool 应该没什么疑问。然后 thread pool 目前的默认值是 4 应该也是对的。

接下来,nodejs 的 event loop 中,poll 阶段负责处理 I/O event 应该也是没什么问题的。然后对应的 callback 应该也是在这个阶段执行。这个阶段会 block 整个 event loop。最长的 block 时间我记不清了,可能需要查一下资料。

然后为了避免是读同一个文件的问题,我生成了很多个一样的 150M 的文件。同样循环去读,下面是例子用到的代码:

const fs = require('fs');
const COUNT = 16;

for (let i = 1; i <= COUNT; ++i) {
    console.time(i);
    console.log(process.hrtime());
    fs.readFile(`a${i}`, (err, data) => {
        console.log(process.hrtime());
        console.timeEnd(i);
    });
}

执行的时候通过环境变量设置 thread pool size 为 1,UV_THREADPOOL_SIZE=1。然后会发现这个 COUNT 不管设置多少,callback 们的时间都是差不多的。例如我尝试了 128,这时候每个 callback 里面的时间都是 4s 多了,我猜是已经超过了上文提到的 poll 阶段的最大 block 时间。

然后就比较奇怪了,目前 pool size 是 1,但是还是所有的 callback 一起触发。如果中间有 poll 阶段(毕竟已经 4s 多了,不过我晚点查一下资料再确认一下),并且有已经完成的读取,那么 callback 应该会被触发才对吧。

不知道是不是我的理解出了什么问题,晚点再更新,TODO。


我还是没有找到相关的资料。我在 stackoverflow 上提问求助了,不过似乎还没得到靠谱的答案。具体问题在这里

其中有人提到了 node 在读多个文件的时候,那些小的 chunk 会被穿插执行,所以看起来像是多个文件一起在读。不过我觉得既然 poll size 只有 1,应该不是在同时读多个文件才对。

我继续问问朋友。持续关注,如果题主有答案了也欢迎告诉我。

新手上路,请多包涵

我这边mac是一批一批的出来的:

TedMacdeMacBook-Pro:nodecpu100 tedmac$ node app.js 
Example app listening on port 3002!
node已接受到请求--id  1
node已接受到请求--id  2
node已接受到请求--id  3
node已接受到请求--id  4
node已接受到请求--id  5
node已接受到请求--id  6
异步读取完成
node已接受到请求--id  7
异步读取完成
node已接受到请求--id  8
异步读取完成
node已接受到请求--id  9
异步读取完成
异步读取完成
异步读取完成
异步读取完成
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏