【发布时间】:2020-04-04 01:24:41
【问题描述】:
我有一个应用程序,它必须从视频中提取颜色信息,它通过分析每一帧来做到这一点。首先,我提取帧,然后将它们的位置数组加载到内存中。正如您可能想象的那样,即使是一个小视频也可能有数千个。
我用来提取每个帧颜色信息的函数是一个承诺,所以我选择使用 Promise.all 批量处理一组承诺
对于每个文件的绝对路径,我使用fs 读取文件,然后将其传递以进行处理。我已经使用许多独立图像完成了此操作,并且知道该过程只需要大约一秒钟,但突然间处理一张图像需要将近 20 分钟。我终于发现在fs.readFile 上使用promisify 是导致瓶颈的原因。我不明白为什么?
在第一个中,fs.readFile 在返回的 promise 内部进行了转换,而在第二个中,fs.readFile 只是正常使用,我等待调用 resolve。我不介意使用 non-promise 的,我只是好奇为什么这会导致这么慢?
在我停止使用promisify 的那一刻,应用程序速度恢复到 1 帧/秒
慢代码:
async analyzeVideo(){
await this._saveVideo();
await this._extractFrames();
await this._removeVideo();
const colorPromises = this.frameExtractor.frames.map(file => {
return new Promise(resolve => {
//transform image into data
const readFile = promisify(fs.readFile);
readFile(file)
.then(data => {
const analyzer = new ColorAnalyzer(data);
analyzer.init()
.then(colors => {
resolve(colors)
})
})
.catch((e)=> console.log(e));
})
});
const colors = await runAllQueries(colorPromises);
await this._removeFrames();
this.colors = colors;
async function runAllQueries(promises) {
const batches = _.chunk(promises, 50);
const results = [];
while (batches.length) {
const batch = batches.shift();
const result = await Promise.all(batch)
.catch(e=>console.log(e));
results.push(result)
}
return _.flatten(results);
}
}
快速代码:
async analyzeVideo(){
await this._saveVideo();
await this._extractFrames();
await this._removeVideo();
const colorPromises = this.frameExtractor.frames.map(file => {
return new Promise(resolve => {
//transform image into data
fs.readFile(file, (err, data) => {
const analyzer = new ColorAnalyzer(data);
analyzer.init()
.then(colors => {
resolve(colors)
})
});
})
});
const colors = await runAllQueries(colorPromises);
await this._removeFrames();
this.colors = colors;
async function runAllQueries(promises) {
const batches = _.chunk(promises, 50);
const results = [];
while (batches.length) {
const batch = batches.shift();
const result = await Promise.all(batch)
.catch(e=>console.log(e));
results.push(result)
}
return _.flatten(results);
}
}
【问题讨论】:
-
我怀疑是不是这个问题,但你不需要
promisifyfs.readFileN 次,在模块开头做一次。 -
@MarcosCasagrande 这实际上是我发现 promisify 是问题所在。当我将它包含在
new Promise()之外时,它在实际调用承诺时是未定义的 -
您的
runAllQueries没有意义。当您调用该函数时,所有readFile调用已经在运行,您已经创建了 Promise。 -
@Bergi
colorPromises持有承诺,但不会执行。 -
@KAT 承诺不是可以“执行”的东西。它代表已经开始计算的结果,可以等待,仅此而已。
Promise.all不会“执行”任何东西,它只是创建一个新的承诺,等待所有个人承诺。立即执行执行器回调的是new Promise调用。
标签: node.js asynchronous promise node-promisify