共计 1473 个字符,预计需要花费 4 分钟才能阅读完成。
之前做过一个 Node.js 实现分片上传 的性能。过后前端采纳文件切片后并发上传,大大提高了上传的速度,应用 Promise.race() 治理并发池,无效防止浏览器内存耗尽。
当初的问题:Node.js 服务端合并大文件分片 内存耗尽导致服务重启
服务端代码
const ws = fs.createWriteStream(`${target}/${filename}`); // 创立将要写入文件分片的流
const bufferList = fs.readdirSync(`${STATIC_TEMPORARY}/${filename}`); // 读取到分片文件名的列表 [1,2,3...] 每个分片 1M 大小
// 2. 不会阻塞 EventLoop
bufferList.forEach((hash, index) => {fs.readFile(`${STATIC_TEMPORARY}/${filename}/${index}`, (err, data) => {ws.write(data);
});
});
服务器配置:RAM:1024MB 1vCPU(运行了一些其余服务)
测试发现只有上传的文件超过 300M,在合并分片时就会导致内存耗尽服务重启,根本无法实现分片合并。
解决方案:能不能在循环中管制读取文件的并发数呢? 这样就不会有大量文件同时读取到内存中导致服务解体了。
尝试像前端那样应用 Promise.race 管制:
const ws = fs.createWriteStream(`${target}/${filename}`); // 创立将要写入文件分片的流
const bufferList = fs.readdirSync(`${STATIC_TEMPORARY}/${filename}`); // 读取到分片文件名的列表 [1,2,3...] 每个分片 1M 大小
// Promise.race 并发管制
const pool = [];
let finish = 0; // 曾经写入实现的分片数量
// 应用 Promise 包裹读取文件的异步操作
const PR = (index) => {return new Promise((resolve) => {fs.readFile(`${STATIC_TEMPORARY}/${filename}/${index}`, (err, data) => {ws.write(data)
resolve({});
});
});
};
(async function easyRead() {for (let i = 0; i < bufferList.length; i ++) {const task = PR(i).then(val => {
finish+=1
const index = pool.findIndex(t => t === task);
pool.splice(index);
if (finish === bufferList.length) {ws.close();
}
});
pool.push(task);
if (pool.length === 1) { // 这里并发数量只能是 1 否则分片写入是乱序的 格局会被损坏
await Promise.race(pool);
}
}
})()
这时神奇的事件就产生了,咱们在 for 循环中应用了 Promise.race() 管制了同一时间读入到内存中的文件数量。
再次测试,服务曾经不会在合并分片时解体,即便 1 个 G 的文件分片也能够在 3 秒左右合并实现。
总结
晓得 Promise.race() 的人很多,这样的面试题也很多,然而能使用到实际中解决理论的问题却不是很多。
心愿本文能够帮到你。
文章首发于 IICOOM- 技术博客《应用 Promise.race() 实现管制并发》
正文完