Python 协程不与 time.sleep() 同时运行?

Kur*_*eek 5 python coroutine async-await python-asyncio

我正在尝试遵循https://docs.python.org/3/library/asyncio-task.html#coroutines中的示例;这是同时运行两个say_after协程的代码片段:

import asyncio
import time


async def say_after(delay, what):
    await asyncio.sleep(delay)
    # time.sleep(delay)
    print(what)


async def main():
    task1 = asyncio.create_task(say_after(1, 'hello'))
    task2 = asyncio.create_task(say_after(2, 'world'))


    print(f"Started at {time.strftime('%X')}")

    await task1
    await task2

    print(f"Finished at {time.strftime('%X')}")


if __name__ == "__main__":
    asyncio.run(main())
Run Code Online (Sandbox Code Playgroud)

如果我运行这个,我会发现开始和结束相隔两秒:

Started at 12:59:35
hello
world
Finished at 12:59:37
Run Code Online (Sandbox Code Playgroud)

但是,如果我替换await asyncio.sleep(delay)time.sleep(delay)(上面代码片段中的注释行),我会发现它们相隔三秒,因此基本上是同步运行的:

Started at 13:00:53
hello
world
Finished at 13:00:56
Run Code Online (Sandbox Code Playgroud)

我不太明白这一点;即使任务本身包含同步代码,并行运行的并发任务的意义不是吗?为什么这个例子不再适用time.sleep()于而不是asyncio.sleep()

wim*_*wim 5

我不太明白这一点;即使任务本身包含同步代码,并行运行的并发任务的意义不是吗?

并发!=并行。在编写asyncio代码时,底层例程仍然必须将流程返回到事件循环以允许并发。不管怎样,GIL 仍然存在。

为什么此示例不再使用 time.sleep() 而不是 asyncio.sleep()?

这里的区别在于asyncio.sleep挂起当前任务,允许其他任务运行。time.sleep不,这是一个“阻塞”调用。使用的程序asyncio仍然是单线程的(除非使用线程),这意味着time.sleep阻止主线程中的执行并阻止整个程序,直到睡眠持续时间结束。

协程提供协作并发,而不是并行。

为了通过协程实现良好的并发性,协程中调用的任何代码都asyncio.run必须以非阻塞方式编写。实际上,这意味着任务中运行的任何代码都有责任在暂停执行的好时机时让出,例如“我没有做任何有用的事情,因为我只是在等待 I/O ”,从而允许另一个任务使用事件循环。

  • 需要明确的一点是:“asyncio”是“合作”并发;如果您不执行某些操作来显式地将控制权交还给事件循环(例如使用“await”),那么事件循环将没有机会运行其他任何内容,直到您的代码*完成*。如果您选择阻止某些不是异步可等待的事情,则事件循环无法知道它*可以*做其他事情,因此它只是一直等待您将控制权交还给它。 (2认同)