Javascript 在使用IO操作时,如何避免任务使libuv过饱和

Javascript 在使用IO操作时,如何避免任务使libuv过饱和,javascript,typescript,asynchronous,libuv,Javascript,Typescript,Asynchronous,Libuv,我正在使用Typescript,因此libuv来执行任何IO操作。在我的特定场景中,我对给定文件进行指纹哈希。为了对我的问题作一点说明,请考虑输入文件是 1Tb的文件。要获取文件的指纹,我可以通过文件流打开文件并更新哈希: return new Promise((resolve, reject) => { const hash = crypto.createHash('sha256'); const fh = fse.createReadStream(filepath, {

我正在使用Typescript,因此
libuv
来执行任何IO操作。在我的特定场景中,我对给定文件进行指纹哈希。为了对我的问题作一点说明,请考虑输入文件是<强> 1Tb的文件。要获取文件的指纹,我可以通过文件流打开文件并更新哈希:

return new Promise((resolve, reject) => {
    const hash = crypto.createHash('sha256');
    const fh = fse.createReadStream(filepath, {
        highWaterMark : 100000000
    });

    fh.on('data', (d) => { hash.update(d); });
    fh.on('end', () => {
        resolve(hash);
    });
    fh.on('error', reject);
});
上面的例子是相当缓慢的,因为它的顺序方法。所以我想的一个更快的方法是将计算分成N个块,如下所示:

let promises = [];
for (let i = 0; i < N; ++i) {
    promises.push(calculateFilePart(file, from, to));
}
return Promise.all(all);
let promissions=[];
for(设i=0;i
在上面的示例中,假设
N
为1000000,这是否意味着
libuv
同时在后台启动1000000个异步I/O操作?或者libuv是否会自动成批地将它们排队,以避免IO请求的过度饱和


非常感谢您对本主题的任何帮助

我将尽可能简要地总结一些关键概念。我将在下面留下链接供参考,以便您可以验证事实

Promise将任务添加到称为微任务队列的东西中。在事件循环的每次迭代中,当调用堆栈为空时,将处理来自微任务队列的任务。这被称为
勾选
。所以,每次勾选,都会处理微任务队列中的一些任务

对于每个进程标记,都有一个最大深度(
process.maxTickDepth
)。这指定要从微任务队列卸载并推入调用堆栈的任务数

算法的主要部分包括读取作为I/O操作的内容。这些操作被推送到一个称为宏任务队列的单独队列中。当schedule宏任务操作完成并且具有指定的内容块时,读取操作的事件处理程序将排队到Microtask队列中,以便在下一次勾选时进行处理

给定代码段和约束条件,如果最大深度为1000,则需要传递至少
N/1000=1000000/1000=1000
个记号,才能使算法完全更新哈希。这意味着Node.js进程将只处理每个刻度的特定数量的任务

我希望这能给你提供你想要的理解

参考资料:


谢谢!这是一个了不起的见解!我将查看您的链接,因此如果我理解正确,
libuv
将自行处理宏任务,因此如果我在
libuv
上推送bizillion
async readFile(…)
操作,则无需担心,因为它只会通过内部限制来限制真正的并行执行,并成批执行。我总结得对吗?我想是的。我自己对迄今为止所遇到的所有材料的理解和知识表明。