node.js是否在主线程中运行异步文件读/写?

blz*_*blz 5 javascript multithreading asynchronous node.js

我原以为读取文件等异步处理在其他线程上处理,在其他线程读完时通知主线程.

我试过跟随.

const fs = require("fs")

console.time(1)
fs.readFile("largefile", x => console.timeEnd(1))
Run Code Online (Sandbox Code Playgroud)

这表明1500ms.

其次我试着跟随.

const fs = require("fs")

console.time(1)
fs.readFile("largefile", x => console.timeEnd(1))

// block main thread 1sec
const s = Date.now()
while(Date.now() - s < 1000);
Run Code Online (Sandbox Code Playgroud)

它将显示1500ms是否在其他线程上处理异步进程.但是,我得到了2500ms.

我尝试了另一个.

const fs = require("fs")

console.time(1)
fs.readFile("largefile", x => console.timeEnd(1))

setInterval(() => {
    const s = Date.now()
    while(Date.now() - s < 100);
}, 100)
Run Code Online (Sandbox Code Playgroud)

我等了几分钟,但没有消息.

nodejs是否在主线程上处理繁重的处理?

child_process当我需要读取和写入太多大文件时,我应该使用吗?

T.J*_*der 6

I/O是在封面下使用非阻塞操作完成的(而不是占用主线程); 但是,I/O 完成(例如,回调)是在启动I/O操作的线程上完成的(在您的示例中,一个主要的JavaScript线程,因为您没有使用worker).如果你使该线程饱和,它就没有机会处理回调.

你的例子中的主要问题是

  1. 您正在使用便利功能,readFile一次性将大文件读入内存.

  2. 您的测试是合成的,执行极其耗费CPU的事情,不太可能模拟您的实际应用程序的特征.

nodejs是否在主线程上处理繁重的处理?

方便函数的某些部分readFile是在您调用它的线程(在您的示例中为主线程)上实现的,是的.readFile是使用JavaScript实现的fs.read,它在处理完前一个块之前不会请求下一个数据块; 块的默认大小(截至本文时)为8k(8,192)字节.

你可以在源代码中看到这个:

这意味着如果主线程被阻塞(你的第二个代码块)或负载极重(你的第三个代码块),处理每8k一次的read回调非常慢,这会极大地影响便利功能的性能:

  • 你的第二个代码块(1,000ms忙等待)阻止了对前8k数据的第一个回调的处理,因此它阻止了整个1,000ms的读取过程,在此过程中它被阻塞.
  • 你的第三个代码块(setInterval呼叫忙等待每100毫秒100毫秒)与readFile实现相结合,在从文件读取的每个8k块之间引入~100ms的延迟.任何大小的文件都需要长时间才能以~820字节/秒的速度读取.

但是,你的测试再次是合成的.即使是一次100毫秒阻塞主线程也是不寻常的.

当我需要读取和写入太多大文件时,我应该使用child_process吗?

号使用基本I/O操作(只要做到这一点的合理大小的块read,write),而不是使用像方便的功能readFile.使用子进程至少与使用工作线程一样糟糕,如果不是更糟,Node.js开发团队在工作线程文档中有这个说法:

worker对于执行CPU密集型JavaScript操作很有用; 不要将它们用于I/O,因为Node.js用于异步执行操作的内置机制已经比工作线程更有效地处理它.