【问题标题】:asyncio.create_task vs awaitasyncio.create_task 与等待
【发布时间】:2018-08-03 21:17:38
【问题描述】:

我无法理解 Python 3.7 中引入的 asyncio.create_task() 函数应该如何工作。如果我这样做:

import asyncio

async def helloworld():
    print("Hello world from a coroutine!")
    asyncio.create_task(helloworld())

def main():
    loop = asyncio.get_event_loop()
    loop.run_until_complete(helloworld())

if __name__ == "__main__":
    main()

我明白了:

Hello world from a coroutine! Hello world from a coroutine!

作为输出(即协程运行两次)。这怎么不是无限递归呢?当我使用 await 关键字时,我希望看到我看到的内容:

import asyncio


async def helloworld():
    print("Hello world from a coroutine!")
    await helloworld()


def main():
    loop = asyncio.get_event_loop()
    loop.run_until_complete(helloworld())


if __name__ == "__main__":
    main()

这样我得到:

Hello world from a coroutine! Hello world from a coroutine! Hello world from a coroutine! ... many more lines... Traceback (most recent call last): File "test3.py", line 53, in <module> main() File "test3.py", line 48, in main loop.run_until_complete(helloworld()) File "/usr/local/Cellar/python/3.7.0/Frameworks/Python.framework/Versions/3.7/lib/python3.7/asyncio/base_events.py", line 568, in run_until_complete return future.result() File "test3.py", line 37, in helloworld await helloworld() File "test3.py", line 37, in helloworld await helloworld() File "test3.py", line 37, in helloworld await helloworld() [Previous line repeated 984 more times] File "test3.py", line 36, in helloworld print("Hello world from a coroutine!") RecursionError: maximum recursion depth exceeded while calling a Python object

create_task 是如何只被调度一次的,什么情况下可以使用它(因为它必须在事件循环已经运行的上下文中运行)?

【问题讨论】:

    标签: python python-asyncio


    【解决方案1】:

    任务没有安排一次,但循环只运行到helloworld 完成。您会看到消息打印两次,因为循环允许下一个任务运行。之后,任务停止运行,因为循环不再运行。

    如果你改变了

    loop.run_until_complete(helloworld())
    

    loop.create_task(helloworld())
    loop.run_forever()
    

    您会看到Hello world from a coroutine! 反复打印出来。

    【讨论】:

    • 对,所以第二次进入helloworld,我们安排了另一次运行,但由于run_until_complete 完成,控制权返回给main()。谢谢!
    • “您会看到消息打印两次,因为循环允许下一个任务运行。” -- 这是偶然的(竞态条件下未定义的行为),还是预期的行为,例如:完成所有已启动的任务,同时默默地忽略对create_task的新调用?
    • 没有解释为什么循环只让下一个任务运行而不是任何后续任务。
    • @GamefanA 因为一旦第一个任务注册了第二个任务,它就完成了。此时,run_until_,complete 满足并停止运行循环。
    • @dirn 这是我脑海中的场景。运行第一个任务,打印并安排第二个任务。如果如您所说,并且第一个任务现在已经完成,那么循环应该立即退出,甚至不尝试第二个,即使它已排队。但这不会发生!就好像第一个任务没有在最后终止,而是产生并给了第二个任务运行的机会,这反过来又安排了第三个任务,依此类推……我能想到的唯一解释是第一个任务让给第二个,第二个让给第一个,然后第一个终止。
    【解决方案2】:

    您可以将asyncio.create_task 视为多线程世界中的守护线程。当“主”协程停止时,循环停止。所以其他守护线程无论如何都会退出。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-11-01
      • 1970-01-01
      • 2021-09-04
      • 2014-04-04
      • 1970-01-01
      • 2021-09-19
      相关资源
      最近更新 更多