Node.js NodeJs/Express:避免顺序处理许多文件

Node.js NodeJs/Express:避免顺序处理许多文件,node.js,express,multiprocessing,Node.js,Express,Multiprocessing,我有一个很少被调用的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'); } 循环的每次迭代都需要几分

我有一个很少被调用的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.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');
}
虽然同时做每件事相对简单,但它可能会占用大量资源。目前尚不清楚
下载
转换
上传
在内部是如何工作的,但很可能会达到机器资源的极限。为了避免诸如达到打开文件限制或内存不足之类的情况,应该限制并发处理的项目数

一种方法是分批处理项目。要成批处理,您可以简单地将
文件数组
分割成块,并将上面的解决方案与迭代解决方案相结合

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');
});

您可以使用
Array.prototype.map
Promise.all
同时处理所有内容。同时执行所有操作可能会占用大量资源,因此您可能希望成批处理,或某种基于队列的处理,但这取决于您的需求。我原以为我需要生成更多节点进程来并行执行工作?或者是队列/批处理?假设
下载
转换
,和
上传
是真正异步的,您不需要额外的节点进程。如果你正在运行的代码中的任何一个(例如,同步,需要很长的时间运行),那么你可能想考虑分叉点。非常感谢你的帮助。谢谢这个伟大的答案。它不仅运行良好,而且具有教育意义。