当我在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/

10-15 14:15