代码之家  ›  专栏  ›  技术社区  ›  jsstuball

如何在Asyncio3.7中将多个任务添加到主协同程序中?

  •  0
  • jsstuball  · 技术社区  · 5 年前

    我正在尝试将代码从asyncio3.6更新到asyncio3.7。 过渡的一个哲学元素是强烈鼓励在程序中使用单个入口点,特别是单个入口点 asyncio.run(main()) .

    此程序工作:

    import asyncio
    
    async def foo():
        while True:
            await asyncio.sleep(1)
            print("hi")
    
    asyncio.run(foo())
    

    这个程序可以工作:

    import asyncio
    
    async def foo():
        while True:
            await asyncio.sleep(1)
            print("hi")
    
    async def main():
        await foo()
    
    asyncio.run(main())
    

    但在打印任何内容之前,以下程序不出错地退出:

    import asyncio
    
    async def foo():
        while True:
            await asyncio.sleep(1)
            print("hi")
    
    async def bar():
        while True:
            await asyncio.sleep(1)
            print("ho")
    
    async def main():
        asyncio.create_task(foo())
        asyncio.create_task(bar())
    
    asyncio.run(main())
    

    Asyncio3.7是否规定了让MAIN等待未来的最佳实践,也就是说,在发生错误时进行设置?

    我知道加一些 await future 排在底部的主程序使第三个程序“工作”,但我仍然不满意的使用 create_task 对于main中的无限协程,拥有一个入口点的全部意义就是您可以在一个点捕获程序引发的所有未处理的异常。但是当你有这样的“悬空”任务时,它并不能抑制 set_exception_handler 在循环上。

    1 回复  |  直到 5 年前
        1
  •  2
  •   user4815162342    5 年前

    在这种情况下,您只需要如下内容:

    async def main():
        # wait for both `foo()` and `bar()` to finish
        await asyncio.gather(foo(), bar())
    

    您也可以使用 asyncio.wait(return_when=asyncio.FIRST_COMPLETED) 等到 任何一个 foo() bar() 完成,但这需要额外的注意才能实际检索结果,以便正确传播异常。

    等待一个明确的未来是更高级的用法,当退出程序的决定必须在一个深度嵌套的回调中作出时最合适。