能否将列表传入asyncio.gather?如何用循环批量启动并行协程
问题原因
你遇到的报错是几个基础用法错误导致的:
main是普通同步函数,没有用async关键字声明,调用后返回None,但asyncio.run()要求传入协程对象,这是报错的直接诱因。asyncio.gather()本身是协程函数,必须用await调用才会执行内部的协程任务,你原代码仅调用了gather没有等待执行,就算解决第一个问题也不会跑串口任务。- 额外冗余/隐患:Python 3.7+ 用
asyncio.run()时不需要手动获取事件循环,gather的loop参数已在高版本弃用;另外你循环里的未知协议分支没有跳过后续逻辑,遇到未知协议会触发类型错误。
修正后的代码
# -*- coding: utf-8 -*- import asyncio import aioserial from protocol import contactid, ademco # 补充原代码缺失的导入 import utils import log async def main(): centrals = utils.auth() lst_coro = [] for central in centrals: protocol = central['protocol'] id = central['id'] name = central['name'] port = central['port'] logger = log.create_logging_system(name) # 匹配协议处理函数 if protocol == 'contactid': process_func = contactid.process elif protocol == 'ademco': process_func = ademco.process else: print(f'Unknown protocol: {protocol}') continue # 未知协议跳过后续逻辑 # 解析串口参数 dev = ''.join(['/dev/', *filter(str.isalnum, port.split('/')[0])]) bps = int(port.split('/')[-1]) aioserial_instance = aioserial.AioSerial(port=dev, baudrate=bps) lst_coro.append(process_func(aioserial_instance, id, name, logger)) # 等待所有协程执行完成 await asyncio.gather(*lst_coro) if __name__ == '__main__': asyncio.run(main())
批量启动协程的最优方式
你原方案用列表存储循环生成的协程是官方推荐的标准写法,完全不需要换成集合:
- 如果需要捕获单个协程的异常不影响其他任务,可以给
gather加return_exceptions=True参数 - 如果需要动态添加/取消任务,可以用
asyncio.create_task()把协程包装成任务对象再存入列表,后续可以单独控制每个任务的生命周期
内容的提问来源于stack exchange,提问作者Guilherme Richter
相关产品推荐
相关产品推荐

