Asyncio与Concurrent Futures性能差异显著?Python异步优化问题咨询
异步优化Python代码的性能差异问题
我尝试通过异步方式优化Python代码,分别使用了asyncio和concurrent.futures库,测试结果差异明显:
- 无asyncio的同步版本耗时约22秒
- 使用asyncio的版本耗时约20秒
- 使用concurrent.futures的版本仅耗时约3秒
以下是我的代码:
asyncio版本代码
async def get_rds_instances(session, region, engine_types): report_rds = [] mandatory_tags = {'Use-Case'} client = session.client('rds', region_name=region) try: await asyncio.sleep(1) response = client.describe_db_instances() rds_report.append(response) except (ClientError, Exception) as e: print(e) return reportd_rds async def main(): ... some arguments definition session = get_rds_session(profile_name) regions = session.get_available_regions('rds') try: reports = await asyncio.gather(*[get_rds_instances(session=session, region=region, engine_types=engine_types) for region in regions]) except Exception as e: print(f"An error occurred: {str(e)}") ... process report if __name__ == "__main__": asyncio.run(main())
concurrent.futures版本代码
def get_rds_instances(session, region, engine_types): report_rds = [] mandatory_tags = {'Use-Case'} client = session.client('rds', region_name=region) try: response = client.describe_db_instances() rds_report.append(response) except (ClientError, Exception) as e: print(e) return reportd_rds def main(): ... some arguments definition session = get_rds_session(profile_name) regions = session.get_available_regions('rds') try: args = ((session, region, engine_types) for region in regions) with concurrent.futures.ThreadPoolExecutor() as executor: reports = executor.map(lambda p: get_rds_instances(*p), args) except Exception as e: print(f"An error occurred: {str(e)}") ... process report if __name__ == "__main__": main()
请问这种性能差异是否正常?我在使用asyncio时是否存在疏漏或错误?
编辑:描述RDS实例(对应原接口describe_db_instances)
问题解答
这种性能差异完全正常,你的asyncio版本没有真正实现异步IO,核心问题有两个:
使用了boto3同步客户端:
client.describe_db_instances()是阻塞式的同步调用,它会占用asyncio的事件循环线程,导致其他任务无法执行——直到这个同步调用完成,事件循环才能继续处理下一个任务。这就相当于把同步代码套了一层async的壳,根本没发挥异步的优势,所以耗时和同步版本几乎一致。代码中的低级错误:你的asyncio代码里存在变量名拼写错误(比如
report_rds和rds_report、reportd_rds不统一),不过这不会影响性能,只是会导致运行报错。
而concurrent.futures的ThreadPoolExecutor版本能快速运行的原因是:boto3的同步调用属于IO密集型操作,在等待AWS返回响应时,Python的GIL会被释放,线程池可以同时处理多个请求,实现并行的IO等待,所以耗时大幅降低。
如果想让asyncio版本达到类似的性能,有两种解决方案:
- 使用aioboto3(boto3的异步版本),它提供了真正的异步客户端,所有API调用都是async/await风格的非阻塞操作。
- 把boto3的同步调用包装到asyncio的线程池里执行,比如用
await asyncio.to_thread(client.describe_db_instances),这样能让事件循环在等待IO时处理其他任务。
内容的提问来源于stack exchange,提问作者Umut TEKİN
相关产品推荐
相关产品推荐

