【发布时间】:2019-10-05 19:50:12
【问题描述】:
当我在 cpython 3.6 上运行它时,以下程序会打印一次 hello world,然后永远旋转。
作为旁注,取消注释await asyncio.sleep(0) 行会导致它每秒打印hello world,这是可以理解的。
import asyncio
async def do_nothing():
# await asyncio.sleep(0)
pass
async def hog_the_event_loop():
while True:
await do_nothing()
async def timer_print():
while True:
print("hello world")
await asyncio.sleep(1)
loop = asyncio.get_event_loop()
loop.create_task(timer_print())
loop.create_task(hog_the_event_loop())
loop.run_forever()
这种行为(打印hello world 一次)对我来说很有意义,因为hog_the_event_loop 从不阻塞,因此不需要暂停执行。 我可以依赖这种行为吗? 当await do_nothing() 行运行时,是否有可能不是进入do_nothing() 协程,而是执行实际上会暂停和恢复timer_print(),从而导致程序打印hello world 第二次?
更笼统地说:python 什么时候会暂停执行协程并切换到另一个协程?是否有可能任何使用await 关键字?还是仅在导致底层select 调用(例如I/O、睡眠定时器等)的情况下?
补充说明
我知道如果hog_the_event_loop 看起来像这样,它肯定不会让另一个协程执行:
async def hog_the_event_loop():
while True:
pass
我试图具体解决await do_nothing() 是否与上述不同的问题。
【问题讨论】:
-
如果没有
await行,您的hog_the_event_loop在无限循环中只有同步代码。这将阻止事件循环。每次迭代都会到达await,事件循环可以离开协同处理并执行其他等待任务。 -
谢谢。只是为了确保我理解:在
await do_nothing()中仅使用await不符合异步代码的条件,并且不足以像await asyncio.sleep(0)那样导致另一个任务执行? -
必须有一些可以等待的东西。
-
我记得 David Beazley 的一些上下文(但细节很模糊,所以我会留下评论而不是回答):
async/await模型是协作多任务处理的一个示例:一个函数以一种方式实现,以在将控制权交还给事件循环的适当或有用时向函数执行中的点发出信号;该函数使用await发送该信号。可以说,没有await的函数不是“合作”的。 -
关于您的跟进,
await do_nothing()确立了do_nothing()也将参与合作机制的期望。因为它没有,hog_the_event_loop()中的无限循环永远不会放弃控制。这至少是我对此的直观理解;自从我花了很多时间以来已经有一段时间了。
标签: python python-3.x async-await python-asyncio coroutine