【问题标题】:Feels weird for the results of `fs.readFile` IO works in NodeJS thread pool`fs.readFile` IO 在 NodeJS 线程池中工作的结果感觉很奇怪
【发布时间】:2020-05-23 12:33:34
【问题描述】:

我生成了许多具有相同内容和 150M 大小的文件。 我使用fs.readFile async API 像这样读取它们:

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);
    });
}

我已将 ENV 变量 UV_THREADPOOL_SIZE 设置为 1。然后将 COUNT 更改为 8、16 甚至 128。 但回调似乎几乎同时触发。对于128,时间超过4s。

我只测试了 1 个文件,大约需要 60 毫秒。这个截图是 8 个文件的结果:

在我的记忆中,异步fs.readFile API 是由线程池处理的。所以我将池大小更改为 1。

并且在 NodeJS 事件循环中,poll 阶段会处理 IO 事件并为它们执行回调。我忘记了轮询阶段会阻塞事件循环多长时间。但我猜不到 4s。

所以对于上面的代码,我们想异步读取文件。他们同时启动,排队等候接机。由于 poll 大小是 1,我想我们会一个一个地读取所有文件,对吧?如果一个文件已经读取,回调将在下一个轮询阶段执行(对于128个文件,时间超过4s,所以我猜会有下一个轮询阶段)。然后我们将在控制台中获取时间。

但我不明白输出。似乎几乎同时触发了回调。

我对事件循环中的轮询阶段或线程池有什么错误吗?


更新:我知道我可以使用流来优化读取大文件。但问题是当我将线程池设置为 1 时,异步 API 似乎是并行运行的。


更新:感谢@O 的回答。琼斯。他告诉我,nodejs 在读取文件时交错了这些小块。有人可以帮我给我一些关于它的资源吗?或者有谁知道其他信息?

【问题讨论】:

    标签: node.js callback threadpool fs event-loop


    【解决方案1】:

    150 兆字节的数据量很大,因此从磁盘或 SSD 传输到 RAM 需要时间。您的磁盘或 SSD 很可能有某种内部读取请求队列。当您请求多个近乎同时的读取时,它们会进入该队列并一个接一个地进行处理。

    大文件的读取被分解成更小的块读取。看起来节点交错了这些块读取,因此多个readFile 操作大致并行进行。

    在实践中,最好使用流来读取该大小的文件。如果您一次不需要 RAM 中的所有数据,则流很好,因为它们会为每个数据块触发 'data' 事件,并在完成后触发 'close' 事件。看到这个https://nodejs.org/api/fs.html#fs_fs_createreadstream_path_options

    【讨论】:

    • 非常感谢。我将对大文件的多readFile操作进行测试。
    • 我切换到一些1.2M的文件。对于 1 个文件,大约需要 5 毫秒。对于 8 个文件,第一个大约是 9ms,其他大约是 6ms。小块的节点交错真的超出了我的知识。非常感谢你。我可以找到一些文章或来源吗? :)
    • 嗨。我又想了一遍。在我的记忆中,来自事件的任务将在队列中等待接收。但是池子大小是1,那么会不会多读呢?
    猜你喜欢
    • 2019-03-31
    • 2016-05-03
    • 2018-01-15
    • 2013-11-03
    • 1970-01-01
    • 2018-03-11
    • 2016-10-31
    • 2014-08-15
    • 2021-01-11
    相关资源
    最近更新 更多