我正在尝试遵循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())
如果运行此命令,我会发现开始和结束相隔两秒:
Started at 12:59:35
hello
world
Finished at 12:59:37
但是,如果我将await asyncio.sleep(delay)
替换为time.sleep(delay)
(上面代码段中的注释行),我发现它们相距3秒,因此基本上是同步运行的:
Started at 13:00:53
hello
world
Finished at 13:00:56
我不太明白这一点;即使任务本身包含同步代码,让它们并行运行并发任务也没有意义吗?为什么此示例不再适用于time.sleep()
而不是asyncio.sleep()
?
答案 0 :(得分:2)
我不太明白这一点;即使任务本身包含同步代码,并没有使它们并行运行的要点?
并发!=并行性。在编写asyncio
代码时,底层例程仍必须让流返回事件循环,以允许并发。无论如何,GIL仍然在那里。
为什么这个示例不再使用time.sleep()而不是asyncio.sleep()?
asyncio.sleep
暂停当前任务,从而允许其他任务运行。 time.sleep
不会,这是一个阻塞调用(“阻塞”表示它阻塞了主线程中的执行,并且使用asyncio的程序仍然是单线程的。)
协程提供合作并发,而不是并行性。
要通过协程实现良好的并发性,必须以非阻塞方式编写在asyncio.run
中调用的任何代码。实际上,这意味着在任务中运行的任何代码都有责任发出信号,告知何时是暂停执行的适当时间,例如: “我没有做任何有用的事情,因为我正在等待I / O ...”-这允许另一个任务使用事件循环。