我可以将列表传递给 asyncio.gather 吗?

Can I pass an list to asyncio.gather?

我正在尝试使用 forasyncio.gather 启动一堆(一个或多个)aioserial 实例但没有成功。

# -*- coding: utf-8 -*-

import asyncio
import aioserial
from protocol import contactid, ademco

def main():
    #   Loop  Asyncio
    loop = asyncio.get_event_loop()
    centrals = utils.auth()
    #   List of corotines to be executed in paralel
    lst_coro = []
    #   Unpack centrals
    for central in centrals:
        protocol = central['protocol']
        id = central['id']
        name = central['name']
        port = central['port']
        logger = log.create_logging_system(name)
        #   Protocols
        if protocol == 'contactid':
            central = contactid.process
        elif protocol == 'ademco':
            central = ademco.process
        else:
            print(f'Unknown protocol: {central["protocol"]}')
        #  Serial (port ex: ttyUSB0/2400)
        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(central(aioserial_instance, id, name, logger))
    asyncio.gather(*lst_coro, loop=loop)

if __name__ == '__main__':
    asyncio.run(main())

我基于 asyncio documentation 示例和堆栈溢出的一些答案。但是当我尝试 运行 它时,我得到了错误:

Traceback (most recent call last):
  File "/usr/lib/python3.7/runpy.py", line 193, in _run_module_as_main
    "__main__", mod_spec)
  File "/usr/lib/python3.7/runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "/opt/Serial/serial.py", line 39, in <module>
    asyncio.run(main())
  File "/usr/lib/python3.7/asyncio/runners.py", line 37, in run
    raise ValueError("a coroutine was expected, got {!r}".format(main))
ValueError: a coroutine was expected, got None

我也尝试过使用集合而不是列表,但并没有真正改变。当需要使用循环时,有没有更好的方法来启动一堆并行协程?感谢关注

您的问题不在于您如何调用 gather。这取决于您如何定义 main。线索是错误消息

ValueError: a coroutine was expected, got None

以及抛出异常之前回溯中的最后一行代码

asyncio.run(main())

asyncio.run 想要等待。您将 main 的 return 值传递给它,但是 main 没有 return 任何东西。不过,解决方法不是添加 return 值,而是更改定义 main.

的方式
async def main():

这会将 main 从常规函数变为可以等待的 coroutine

编辑

完成此操作后,您会注意到 gather 实际上似乎没有执行任何操作。您需要等待它以便 main 等待 lst_coro 中的所有内容完成。

await asyncio.gather(*lst_coro)

与您的错误无关:您根本不需要在 main 中使用 loopgatherloop 参数在 3.8 中已弃用,并将在 3.10 中删除。除非您使用的是 Python 的旧版本,否则您可以删除它并调用 asyncio.get_event_loop.