AWS Lambda中创建Promise可迭代对象耗时过长的问题咨询
问题分析
你遇到的核心误区是:调用async函数时,并非只返回一个pending状态的Promise就结束——函数内部的同步代码会立即执行,这些同步操作的累加开销才是循环耗时25秒的关键。
具体耗时原因拆解
你循环调用querymetadata()35000次,每次调用都会同步执行以下操作:
- 创建
result空数组、lastEvaluatedKey变量,以及完整的getQuery配置对象(包括嵌套的ExpressionAttributeValues) - 进入
do-while循环,同步执行{ ...getQuery, ExclusiveStartKey: lastEvaluatedKey }的对象展开拷贝 - 调用
docClient.query()方法,AWS SDK内部会同步完成参数校验、请求序列化等前置工作(哪怕后续的网络请求是异步的)
这些看似细碎的同步操作,在35000次循环的累加下,会大量占用Lambda的CPU资源(1GB内存对应的CPU算力有限),直接导致从start到end的耗时被拉长。
优化方案
1. 复用基础查询配置
把固定的查询配置移到函数外部,避免每次调用querymetadata都重复创建和拷贝对象:
// 模块级别复用基础查询配置,只在初始化时创建一次 const BASE_QUERY = { TableName, KeyConditionExpression: "device_id = :device_id", ExpressionAttributeValues: { ":device_id": "EK431", } }; const querymetadata = async() => { let result = [], lastEvaluatedKey = null; do { // 仅在需要时添加ExclusiveStartKey,避免全量对象拷贝 const queryParams = lastEvaluatedKey ? Object.assign({}, BASE_QUERY, { ExclusiveStartKey: lastEvaluatedKey }) : BASE_QUERY; const { Items, LastEvaluatedKey } = await docClient .query(queryParams) .promise(); result = result.concat(Items); lastEvaluatedKey = LastEvaluatedKey; } while (lastEvaluatedKey); console.log(result.length); return result.length; }
2. 分批次创建Promise,缓解同步阻塞
单线程下一次性执行35000次同步操作会持续阻塞事件循环,分批次插入await Promise.resolve()让出CPU时间:
exports.handler = async (event, context) => { console.log('start'); const promises = []; const BATCH_SIZE = 1000; // 每1000个Promise为一批 for(let i = 0; i < 35000; i++) { promises.push(querymetadata()); // 每批结束后让出事件循环,避免同步操作持续占用CPU if ((i + 1) % BATCH_SIZE === 0) { await Promise.resolve(); } } console.log('end'); await Promise.all(promises); console.log('end lambda'); }
3. 优化数组拼接操作(额外小优化)
原代码中result = result.concat(Items)每次都会创建新数组,大数据量下可改为result.push(...Items)减少内存开销:
// 替换 result = result.concat(Items); result.push(...Items);
内容的提问来源于stack exchange,提问作者Judith Joseph
相关产品推荐
相关产品推荐

