gpt4 book ai didi

node.js - 为什么 Promiseify 会导致循环花费更长的时间?

转载 作者:太空宇宙 更新时间:2023-11-03 23:51:33 29 4
gpt4 key购买 nike

我有一个应用程序,它必须从视频中提取颜色信息,它通过分析每一帧来实现这一点。首先,我提取帧,然后将其位置数组加载到内存中。正如您可能想象的那样,即使是一个小视频,其数量也可能达到数千个。

我用来提取每个帧颜色信息的函数是一个 promise ,因此我选择使用 Promise.all 批处理一组 promise

对于每个文件的绝对路径,我使用 fs 读取文件,然后将其传递以进行处理。我对许多独立图像执行过此操作,并且知道该过程只需要大约一秒钟,但突然间处理 1 个图像需要花费近 20 分钟。我终于发现在 fs.readFile 上使用 promisify 是导致瓶颈的原因。我不明白的是为什么?

在第一个中,fs.readFile在返回的promise内部进行了转换,而在第二个中,fs.readFile只是像平常一样使用,我等待调用解析。我不介意使用非 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);
}
}

最佳答案

您不需要在每次循环迭代中promisify,只需在模块顶部执行一次即可。

该问题很可能是由从 Unresolved Promise 引起的。您没有正确处理错误,因此如果抛出错误,Promise.all 可能永远无法完成。

您不必将错误记录在.catch中,而是还必须拒绝,或者至少解决(如果您不关心错误的话)。另外 analyzer.init() 错误没有被捕获(如果该函数可以拒绝)

const readFile = promisify(fs.readFile);
// ...

const colorPromises = this.frameExtractor.frames.map(file => {
return new Promise((resolve, reject) => {
//transform image into data
// const readFile = promisify(fs.readFile);
readFile(file)
.then(data => {
const analyzer = new ColorAnalyzer(data);
return analyzer.init()
})
.then(resolve) // colors
.catch((e)=> {
reject(e);
console.log(e)
});
})
})
<小时/>

除此之外,runAllQueries 并没有做你认为它正在做的事情。你已经履行了所有的 promise 。

我建议您使用p-limit相反

const pLimit = require('p-limit');

const limit = pLimit(50);

/* ... */

const colorPromises = this.frameExtractor.frames.map(file => {
return limit(() => {
return readFile(file)
.then(data => {
const analyzer = new ColorAnalyzer(data);
return analyzer.init()
})
.then(resolve) // colors
})
})

const colors = await Promise.all(colorPromises);

此外,如果您一次执行 50 次读取,则应该增加 UV_THREADPOOL_SIZE 的值。默认为 4。

在您的入口点,在任何要求之前:

process.env.UV_THREADPOOL_SIZE = 64 // up to 128

或者将脚本调用为:UV_THREADPOOL_SIZE=64 node index.js

关于node.js - 为什么 Promiseify 会导致循环花费更长的时间?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59274328/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com