Python asyncio.create_任务vs wait

Python asyncio.create_任务vs wait,python,python-asyncio,Python,Python Asyncio,我很难理解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_comp

我很难理解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()
我得到:

来自合作伙伴的你好!
你好,来自一个合作伙伴的世界

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

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()
有了这个,我得到了:


你好,来自一个合作伙伴的世界!
你好,来自一个合作伙伴的世界!
你好,来自一个合作伙伴的世界!
... 更多的线。。。
回溯(最近一次呼叫最后一次):
文件“test3.py”,第53行,在
main()
文件“test3.py”,第48行,在main中
循环。运行\u直到完成(helloworld())
文件“/usr/local/cillar/python/3.7.0/Frameworks/python.framework/Versions/3.7/lib/python3.7/asyncio/base_events.py”,第568行,运行_直到完成
返回future.result()
helloworld中第37行的文件“test3.py”
等待helloworld()
helloworld中第37行的文件“test3.py”
等待helloworld()
helloworld中第37行的文件“test3.py”
等待helloworld()
[上一行重复984次]
helloworld中第36行的文件“test3.py”
打印(“来自协同程序的Hello world!”)
RecursionError:调用Python对象时超出了最大递归深度


create\u任务如何只调度一次,以及何时可以使用它的用例是什么(因为它必须在事件循环已经运行的上下文中运行)?

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

如果你改变

loop.run_until_complete(helloworld())


您将在协同程序中看到
Hello world重复打印。

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

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