根据 cpu 核心数让 promise.all 执行的更快
在 vue 的源码中看到一段代码,发出感叹,原来可以根据 cpu 核心数让 promise.all 执行的更快!
假设传入 promise.all 的数组参数的长度小于等于 cpu 核心数,那么不需要做额外的操作。
而如果大于 cpu 核心数,那么可以做一些优化操作。
js
async function buildAll(targets) {
await runParallel(require('os').cpus().length, targets, build)
}
// 第一个参数:最大 cpu 核心数
// 第二个参数:执行的脚本任务数量
// 第三个参数:可调用函数
async function runParallel(maxConcurrency, source, iteratorFn) {
const ret = []
const executing = []
// 循环脚本任务
for (const item of source) {
// 将执行脚本任务放入微任务队列中,返回一个 promise
const p = Promise.resolve().then(() => iteratorFn(item, source))
// 将 promise 放入 res 数组中
ret.push(p)
// 如果执行的脚本任务数量大于电脑的 cpu 核心数,
if (source.length >= maxConcurrency) {
// 那么就给当前的 promise 再增加一个 then 成功回调,作用是删除在 executing 数组中的自己。
// 这里需要注意作用域,then 回调里的 e 就是这行代码声明的 e。
const e = p.then(() => executing.splice(executing.indexOf(e), 1))
// 往 executing 数组中推入 promise e
executing.push(e)
// 在 executing 的长度等于电脑 cpu 核心数后,就使用 Promise.race 执行 execting 中的 Promise。
// 这样,就能充分利用 cpu 的核心数,达到最快的速度。
// 原因是 cpu 切换任务执行也是需要耗费时间的。假设一个 cpu 需要执行 3 个任务,
// 并且这 3 个任务的耗时是确定的,
// cpu 的第一种方案是等一个任务执行完后再执行下一个任务快;第二种方案是一个任务完成了一半,cpu 又跑了,去执行另一个任务,来来回回执行完三个任务,来回跑动也耗费了点时间。
// 相比之下,第一种方案更快。
if (executing.length >= maxConcurrency) {
await Promise.race(executing)
}
}
}
return Promise.all(ret)
}