asyncio.create_task 与 await

Ada*_*kin 14 python python-asyncio

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

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()
Run Code Online (Sandbox Code Playgroud)

我得到:

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()
Run Code Online (Sandbox Code Playgroud)

有了这个,我得到:

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_taskonly 是如何调度一次的,以及何时使用它的用例是什么(因为它必须在事件循环已经运行的上下文中运行)?

dir*_*irn 8

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

如果你改变

loop.run_until_complete(helloworld())
Run Code Online (Sandbox Code Playgroud)

loop.create_task(helloworld())
loop.run_forever()
Run Code Online (Sandbox Code Playgroud)

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

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

osp*_*der 5

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