当我在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, sleep 计时器等)的情况下?附加说明
我知道,如果
hog_the_event_loop
看起来像这样,则它肯定不会使执行程序变为另一个协程:async def hog_the_event_loop():
while True:
pass
我正在尝试专门解决
await do_nothing()
是否与以上有所不同的问题。 最佳答案
是的。此行为直接取决于该语言如何指定和实现await
。对于基于async/await的asyncio and other Python库,将其更改为暂停而没有等待对象本身挂起无疑将是一个重大更改。
从调用者的角度来看,任何await
都可以根据等待对象(也称为awaitable)的判断而挂起。因此,是否要暂停特定的await
的最终决定取决于等待的对象(如果是协程,则等待它自己等待,依此类推)。等待一个不选择暂停的等待与运行普通的Python代码相同-它不会将控制权传递给事件循环。
实际暂停的叶子等待通常与IO准备或超时事件有关,但并不总是如此。例如,如果队列为空,则等待queue项将挂起,而等待 run_in_executor
则将挂起,直到在另一个线程中运行的函数完成为止。
值得一提的是,即使指定的延迟为0(即使在指定的延迟为0时,asyncio.sleep
还是explicitly guaranteed都可以挂起执行并推迟到事件循环)(在这种情况下,它将在下一次事件循环通过时立即恢复)。
关于python - Python什么时候/不会暂停协程的执行?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/56204040/