提问人:Alexander Cheprasov 提问时间:9/22/2023 更新时间:9/22/2023 访问量:33
为什么读取 10 个 50 MB 文件所需的时间与在 nodejs 中读取一个 500 MB 文件所需的时间相同?
Why does reading 10 50 MB files take the same amount of time as reading one 500 MB file in nodejs?
问:
// fulfill one promise 5000ms
console.time('test');
(async function () {
await new Promise((resolve) => setTimeout(resolve, 5000));
console.log('slept')
})()
.then(() => {
console.timeEnd('test');
})
// Time ~5000 мс
// fulfill 10 promises by 500ms
console.time('test');
const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let test = [];
(async function () {
test = await Promise.all(
arr.map((elem) => new Promise(async (resolve) => setTimeout(resolve, 500)))
)
console.log(test.length)
console.log('raided')
})()
.then(() => {
console.timeEnd('test');
})
// Time ~500 мс
// Read file 500mb
const fs = require('node:fs');
console.time('test');
let test;
(async function () {
test = fs.readFileSync('./assets/500mb');
console.log('raided', test.length)
})()
.then(() => {
console.timeEnd('test');
})
// Time ~300 мс
// Read 10 files by 50mb
const fs = require('node:fs');
console.time('test');
const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let test = [];
(async function () {
test = await Promise.all(
arr.map((elem) => new Promise((resolve) => fs.readFile(`./assets/50mb_${elem}`, resolve)))
)
console.log(test.length)
console.log('raided')
})()
.then(() => {
console.timeEnd('test');
})
// Time ~300ms
执行完前两个代码后,我们将得到大约 10 倍的执行速度差异。这通常是可以理解的。但是,如果我们读取文件而不是 setTimeout,则不会获得这种增加。为什么?充分解释,我知道读取文件不是由节点完成的,但是那里发生了什么?为什么我们不能获得至少 2 倍的增长?第三和第四个代码的时间是相同的,无论是读取一个 500 MB 的文件还是 10 个 50 MB 的文件都没有区别。为什么?
我试图自己弄清楚,但我无法弄清楚。
答:
0赞
Quentin
9/22/2023
#1
setTimeout
一段时间后调用函数。在调用和调用回调之间的时间里,它不会做任何工作。它只是偶尔检查时钟。setTimeout
readFile
读取文件。当文件被读入内存时,就会调用回调。读取文件是工作。计算机只能如此快速地从磁盘中提取数据。它不能并行读取多个文件,同时为每个文件保持与一次读取一个文件相同的每秒字节数。由于是异步的,它不会阻塞 JS 事件循环,因此 JS 程序可以同时执行其他操作(例如更新显示或通过网络发送消息),但是计算机的磁盘读取部分是任何想要从磁盘读取的东西的瓶颈。readFile
如果你喜欢一个类比:
setTimeout
就像在说“一小时后敲响那个铃铛”。你可以坐在椅子上等待。
readFile
就像说“去学校接孩子,然后叮那个铃铛”,也“去商店买牛奶,然后叮那个铃铛”,也像是“去公园遛神,然后叮那个铃铛”。这些任务中的每一个都需要 1 小时,但您将很难在一小时内完成所有任务。您需要 3 小时才能完成所有 3 个。
评论
0赞
Alexander Cheprasov
9/23/2023
谢谢你的回答,但它也很抽象。我正在寻找一个更深层次的答案,敲响铃铛对我来说是有意义的。但是,从 10 个承诺到与磁盘通信的驱动程序的流程很有趣。我假设密钥在线程或处理器内核中的某个地方。该过程在一个内核上启动,因此对磁盘的所有操作都将在一个内核(线程)上进行,我们不会进行并行工作。但这些都是假设,没人能说出来。
0赞
Quentin
9/23/2023
@AlexanderCheprasov — 不,这是硬件问题。
评论
fs.readFileSync()
async
fs.promises.readFile()