You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何AWS Lambda异步实现的CloudWatch日志仍呈同步顺序?

问题原因及解决方案

核心原因

你的异步代码只是套了async函数的外壳,但核心操作全是同步阻塞的,根本没用到asyncio的异步调度能力,所以日志和同步版本完全一致。

具体来说:

  • _download_image是同步调用,会直接阻塞事件循环,直到下载完成才会继续执行后续代码。
  • monochrome_and_upload和brighten_and_upload如果是同步函数(比如用了boto3同步SDK、同步图像处理库),就算放到asyncio.gather里,也会同步执行——因为asyncio无法调度普通同步函数,会直接把它们当成阻塞任务从头到尾跑完,不会切换到其他协程。
  • asyncio的并发是基于协程挂起的,只有当代码遇到await(等待异步操作)时,事件循环才会切换到其他协程执行。你的代码里没有任何真正的异步等待逻辑,自然和同步代码没区别。

解决步骤

  1. 替换异步IO SDK
    把同步的boto3换成异步版本aioboto3,所有S3下载/上传操作都改成await调用的异步方法,示例:

    async def _download_image(self, image_key, local_path):
        async with aioboto3.client('s3') as s3:
            await s3.download_file(self.bucket_name, image_key, local_path)
    
  2. 包装同步阻塞操作
    如果暂时不想换SDK,或者图像处理是CPU密集型/本地文件操作这类同步任务,用asyncio.to_thread(Python3.9+)或者loop.run_in_executor把同步操作包装成可await的协程,示例:

    # 下载图片改成异步调用
    await asyncio.to_thread(self._download_image, image_key, temp_image_path + "." + image_file_suffix)
    
    # 图像处理任务也包装成可await的
    tasks = [
        asyncio.to_thread(self.bw_image_processor.monochrome_and_upload, temp_image_path + "." + image_file_suffix),
        asyncio.to_thread(self.brighten_image_processor.brighten_and_upload, temp_image_path + "." + image_file_suffix)
    ]
    await asyncio.gather(*tasks)
    

    注:Python3.8没有asyncio.to_thread,可以用以下代码替代:

    loop = asyncio.get_running_loop()
    await loop.run_in_executor(None, self._download_image, image_key, temp_image_path + "." + image_file_suffix)
    
  3. 确保协程函数正确定义
    所有需要异步调度的方法都要定义成async def,并且内部的阻塞操作都要通过await或者线程/进程池包装,不能直接调用同步阻塞函数。

额外说明

Lambda的Python运行环境是单线程事件循环,只有IO密集型的异步操作能发挥并发优势;如果是CPU密集型的图像处理,更适合用多进程(比如concurrent.futures.ProcessPoolExecutor),避免阻塞事件循环。

内容的提问来源于stack exchange,提问作者SSM Tariq

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 07:00:19