node.js - NodeJs / Express:避免对许多文件进行顺序处理
问题描述
我有一个很少被调用的 Express webhook:
app.use('/convert', async (req, res) => {
const files = await getFiles();
for(let file of files) {
await download(file);
await convert(file);
await upload(file)
}
res.send('finished');
}
循环的每次迭代需要几分钟,可能有数百个文件需要处理。我怎样才能在这里避免顺序处理?
非常感谢
解决方案
最简单的做法是同时处理所有内容。该Promise
规范有一些方法可以同时处理多个 Promise,为此我们将要使用Promise.all
.
app.use('/convert', async (req, res) => {
const files = await getFiles();
const promises = files.map(async (file) => {
await download(file);
await convert(file);
await upload(file)
});
await Promise.all(promises);
res.send('finished');
}
虽然一次完成所有事情相对简单,但它可能会占用大量资源。目前尚不清楚download
、convert
和upload
内部如何工作,但您很可能会达到机器资源的限制。为了避免达到打开文件限制或内存不足等问题,应该限制同时处理的项目数量。
一种方法是批量处理项目。要批量处理,您可以简单地将数组拆分files
为块并将上面的解决方案与您的迭代解决方案结合起来。
app.use('/convert', async (req, res) => {
const files = await getFiles();
const chunkSize = 5;
const chunks = [];
while (files.length) {
chunks.push(files.splice(0, chunkSize));
}
for (const chunk of chunks) {
const promises = chunk.map(async (file) => {
await download(file);
await convert(file);
await upload(file)
});
await Promise.all(promises);
}
res.send('finished');
});
上面的实现将等待chunkSize
项目完成处理,然后再将其他项目排队chunkSize
进行处理。因为它等待所有项目完成,所以一些项目可能处理得非常快,但其他项目需要更长的时间。在这种情况下,您最终会利用您的资源。理想情况下,您将始终一次处理chunkSize
项目。为此,您可以将chunkSize
“线程”排队等待处理,每个“线程”将一次处理一个项目,直到没有任何东西需要处理。
async function process(file) {
await download(file);
await convert(file);
await upload(file);
}
async function thread(files) {
while (files.length) {
await process(files.pop());
}
}
app.use('/convert', async (req, res) => {
const files = await getFiles();
let maxConcurrency = 5;
const threads = [];
while (--maxConcurrency) {
threads.push(thread(files));
}
await Promise.all(threads);
res.send('finished');
});
推荐阅读
- c - 使用 GMenu 的菜单中的巨大差距
- angular - 如何使用 Firebase 在数组中推送新项目
- android - Flutter Firebase 错误 Null 资金(FirebaseUser)无法分配给参数,仪表类型 FutureOr
- c++ - 使用大括号进行实例化 - 它是什么以及为什么在这里使用它?
- css - 如何在 inline-flex 元素的一侧创建边距?
- python - Django:您正在使用 staticfiles 应用程序而没有将 STATIC_ROOT 设置设置为文件系统路径
- python - 使用正则表达式逐行搜索纯文本文件并根据匹配项挑选行
- r - 使用 stringr 或 gsub 在字符数据的开头附加一个数字
- visual-studio - 为什么脚本不起作用/在 Web 浏览器(控件/组件)中未按下按钮?
- docker - Docker 中 30000 毫秒后的 Ssh.net 连接超时