如何正确使用asyncio创建任务并通过任务列表实现批量异步执行
asyncio异步调用问题修复方案
现有代码的核心问题
- 异步协程内调用了同步阻塞的
client.get_data()方法:asyncio的事件循环遇到同步阻塞逻辑时会被完全卡住,无法切换到其他协程执行,因此整体执行效率和串行完全一致,无法发挥异步并发优势。 - 之前调整
asyncio.create_task位置报错的原因:asyncio.create_task必须在已经启动的事件循环上下文内调用,如果在同步函数中提前创建task,此时事件循环还未启动,就会抛出协程相关异常。 - 全局变量
data_list的使用没有必要:asyncio.gather会自动按顺序收集所有协程的返回结果,依赖全局变量反而会引入异步并发写的潜在风险。
修复后代码
import asyncio async def api_single_call(client, symbol): # 优先使用客户端提供的异步接口,如果没有异步接口用下方线程池方案执行同步调用 # 方案1:使用原生异步接口 data = await client.get_data_async(symbol=symbol) # 方案2:同步接口转异步(Python3.9+) # data = await asyncio.to_thread(client.get_data, symbol=symbol) # 方案3:同步接口转异步(Python3.8及以下版本兼容) # data = await asyncio.get_event_loop().run_in_executor(None, client.get_data, symbol) return data def get_ticker_list(client): return get_info_tickers(client) async def main(client): tickers = get_ticker_list(client) # 正确的create_task调用位置:事件循环已启动的async函数内部 task_list = [asyncio.create_task(api_single_call(client, symbol)) for symbol in tickers] # 自动收集所有协程返回结果,无需全局变量 data_list = await asyncio.gather(*task_list) print(data_list) asyncio.run(main(client))
关键注意事项
- 如果
client.get_data是HTTP请求类的IO操作,优先替换为异步HTTP客户端实现原生异步调用,比线程池转异步的性能更高。 - 不要在异步协程内执行CPU密集型计算,此类场景不适合用asyncio实现并发,应该使用多进程方案。
内容的提问来源于stack exchange,提问作者H_Zimmer
相关产品推荐
相关产品推荐

