You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Node.js中读取10个50MB文件与1个500MB文件耗时相同的原因?

问题背景

示例1:单个5000ms Promise

// 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 мс

示例2:并行10个500ms Promise

// 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 мс

示例3:同步读取单个500MB文件

// 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 мс

示例4:并行读取10个50MB文件

// 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替换为文件读取操作后,却无法获得这样的速度提升。我知晓文件读取并非由Node.js本身处理,但具体流程是怎样的?为何我们甚至无法获得至少2倍的速度提升?第三段与第四段代码的耗时完全相同,读取1个500MB文件和读取10个各50MB的文件耗时没有区别,这是为什么?


解答

1. setTimeout与文件读取的核心差异

setTimeout是CPU空闲等待任务:它只是告诉操作系统“指定时间后触发回调”,期间Node.js的事件循环完全可以处理其他任务。所以10个500ms的setTimeout并行执行时,总耗时只取决于单个任务的等待时间,和任务数量无关,自然能拿到10倍的效率提升。

而文件读取是IO密集型任务,核心瓶颈不在Node.js,而在存储设备的IO带宽:

  • Node.js调用fs.readFile时,会把读取请求交给操作系统的IO线程池处理,自己回到事件循环等待结果。
  • 但存储设备(SSD/机械硬盘)的总带宽是固定的——比如你的SSD连续读取速度是1.7GB/s,那不管读1个500MB文件还是10个50MB文件,总数据量都是500MB,总耗时都接近 500MB / 1.7GB/s ≈ 300ms。

2. 并行读多文件没提速的原因

  • 存储设备的连续读取优势:如果10个50MB文件是连续存储在磁盘上的,并行读取和单个大文件读取的效率几乎一致;即使文件分散,总数据量相同的情况下,耗时差异也不会明显。
  • 操作系统IO调度优化:当同时发起多个文件读取请求时,操作系统会把这些请求合并成连续的IO操作(如果文件物理地址连续),避免机械硬盘磁头频繁寻道或SSD块寻址的额外开销,实际耗时和读单个大文件差不多。
  • IO线程池的限制:Node.js默认IO线程池大小是4,即使调大线程池数量,存储带宽的瓶颈依然存在——线程再多,设备每秒能读取的数据量是固定的,总耗时不会减少。

3. 同步与异步读取的耗时一致原因

示例3用了fs.readFileSync,这是同步阻塞调用,会让Node.js主线程等待直到文件读取完成;示例4是异步并行读取,虽然执行方式不同,但两者的总数据量相同,且都受限于存储设备的带宽,所以最终耗时接近。

总结来说,setTimeout的并行是“等待时间重叠”,而文件读取的并行是“数据量叠加”,两者的瓶颈完全不同——前者是时间调度,后者是硬件IO带宽。

内容的提问来源于stack exchange,提问作者Alexander Cheprasov

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 09:46:11