创建 promise 的可迭代对象需要更长的时间

Creating iterables of promise takes longer time

提问人:Judith Joseph 提问时间:10/17/2023 最后编辑:Judith Joseph 更新时间:10/23/2023 访问量:66

问:

我正在尝试使用 promise 并行化我的数据库查询。 假设我需要进行 35000+ 数据库查询,并且我正在尝试使用 Promise.all([iterables]) 来实现它。我面临的问题是,创建可迭代对象的循环花费的时间太长(大约 25 秒),而等待承诺解析只需要 15 秒。 我不明白为什么 for 循环需要这么长时间,因为根据我的理解,它只是附加到 promise 数组并使 promise 处于待处理状态。 我正在使用内存为 1GB 且超时 1 分钟的 aws lambda 函数。

这是我的示例代码:

const querymetadata = async() => {
      let result = [],
      lastEvaluatedKey = null;
      const getQuery = {
        TableName,
        KeyConditionExpression: "device_id = :device_id",
        ExpressionAttributeValues: {
            ":device_id": "EK431",
        }
      };
      do {
        const { Items, LastEvaluatedKey } = await docClient
          .query({ ...getQuery, ExclusiveStartKey: lastEvaluatedKey })
          .promise();
        result = result.concat(Items);
        lastEvaluatedKey = LastEvaluatedKey;
      } while (lastEvaluatedKey);
    console.log(result.length);
    return result.length;
}
exports.handler = async (event, context) => {
    console.log('start');
    for(let i = 0; i < 35000; i++) {
      promises.push(querymetadata());
    }
    console.log('end');
    await Promise.all(promises);    
    console.log('end lambda');
}

在上面的代码中,从开始到结束控制台所花费的时间是 25 秒

我已经在aws lambda函数中尝试了上述代码。我不明白为什么需要这么长时间才能创建承诺可迭代对象

JavaScript 节点 .js 并发 承诺

评论

2赞 Nick Parsons 10/17/2023
你能分享一下吗?也许它正在做一些同步。dbQueryFunction
0赞 Jaromanda X 10/17/2023
基本上,输入的代码在返回之前需要 0.71 毫秒 - 在我的计算机上,就像你在那里做的那样:p//...database queryfor (let i = 0; i < 2500000; i++);
0赞 Judith Joseph 10/17/2023
@NickParsons,它只是 dynamoDB 查询。仅此而已。基本上像: const dbQueryFunction = async () => { await dynamoDBClient.query({...queryparam}).promise() }
0赞 Judith Joseph 10/17/2023
@JaromandaX,但在这里我使用 Promise 进行并行化,对吗?为什么 promise 创建数组需要时间,因为它只是调用函数并将其移动到待处理状态,然后等待它被填满或拒绝,对吧?await 语句应该需要时间,因为它将等待响应,在我的情况下,loop 和 await 语句都需要时间
0赞 Nick Parsons 10/17/2023
@JudithJoseph嗯,是的,我没有看到该代码中有任何阻塞。但是,如果这是其中唯一的一行,则您的函数实际上应该是,如果后面没有任何代码,则无需使用,因此您可以删除(此外,如果您的箭头函数有一个正文,如果您不希望函数返回,则应从该正文显式删除)。不过,我怀疑这些变化会大大加快速度const dbQueryFunction = () => dynamoDBClient.query({...queryparam}).promise();awaitasyncreturnundefined

答:

0赞 Antony Lemmens 10/23/2023 #1

使用您的代码,所有 promise 都会同时排队,然后当您调用“await”时,它们就会开始。 最好创建某种队列。

这是一个非常基本的例子,它并行执行了 3 个操作并等待最终结果,包括所有内容:

function op(id) {
    return new Promise((resolve) => {
        setTimeout(() => {
            resolve(`ok ${id}`)
        }, 1000)
    })
}

const MAX_CONCURRENT = 3
let pendingCount = 0
const results = []

function runNextOp(finalResolve) {
    if ((pendingCount < MAX_CONCURRENT) && (actionsParam.length > 0)) {
        const p = actionsParam.shift()

        op(p).then((res) => {
            results.push([p, res])
            pendingCount -= 1
            runNextOp(finalResolve)

            if ((pendingCount === 0) && (actionsParam.length === 0)) {
                finalResolve(results)
            }
        })

        pendingCount += 1
    }
}

const actionsParam = [1, 2, 3, 4, 5]

function allOps() {
    return new Promise((finalResolve) => {
        for (let i = 0; i < MAX_CONCURRENT; i += 1) {
            runNextOp(finalResolve)
        }
    })
}

(async () => {
    const allResult = await allOps()
    console.log(allResult)
})()