gpt4 book ai didi

python - await 是否总是让其他任务有机会执行?

转载 作者:行者123 更新时间:2023-12-04 11:06:38 28 4
gpt4 key购买 nike

我想知道当事件循环切换任务时 python 提供了什么保证。

据我了解async/await与线程的显着不同之处在于事件循环不会基于时间片切换任务,这意味着除非任务产生( await ),否则它将无限期地进行。这实际上很有用,因为在 asyncio 下管理关键部分比使用线程更容易。

我不太清楚的是以下内容:

async def caller():
while True:
await callee()


async def callee():
pass

在此示例中 caller反复 await .所以从技术上讲,它正在屈服。但我不清楚这是否会允许事件循环上的其他任务执行,因为它只会产生 callee。那是永远不会屈服的。

那就是如果我等待 callee在“关键部分”内,即使我知道它不会阻塞,我是否有发生其他意外事件的风险?

最佳答案

你保持警惕是对的。 caller来自 callee 的 yield ,并屈服于事件循环。然后事件循环决定恢复哪个任务。其他任务可能(希望)在调用 callee 之间进行。 . callee需要等待实际阻塞 Awaitableasyncio.Futureasyncio.sleep() , 不是 协程,否则直到 caller 才会将控件返回到事件循环返回。

例如,以下代码将完成 caller2开始处理 caller1 之前的任务任务。因为callee2本质上是一个同步函数,无需等待阻塞 I/O 操作,因此,不会创建挂起点,caller2将在每次调用 callee2 后立即恢复.

import asyncio
import time

async def caller1():
for i in range(5):
await callee1()

async def callee1():
await asyncio.sleep(1)
print(f"called at {time.strftime('%X')}")

async def caller2():
for i in range(5):
await callee2()

async def callee2():
time.sleep(1)
print(f"sync called at {time.strftime('%X')}")

async def main():
task1 = asyncio.create_task(caller1())
task2 = asyncio.create_task(caller2())
await task1
await task2

asyncio.run(main())


结果:
sync called at 19:23:39
sync called at 19:23:40
sync called at 19:23:41
sync called at 19:23:42
sync called at 19:23:43
called at 19:23:43
called at 19:23:44
called at 19:23:45
called at 19:23:46
called at 19:23:47

但是如果 callee2 等待如下,即使等待 asyncio.sleep(0)也会发生任务切换,并且任务将同时运行。

async def callee2():
await asyncio.sleep(1)
print('sync called')

结果:
called at 19:22:52
sync called at 19:22:52
called at 19:22:53
sync called at 19:22:53
called at 19:22:54
sync called at 19:22:54
called at 19:22:55
sync called at 19:22:55
called at 19:22:56
sync called at 19:22:56

这种行为不一定是直观的,但考虑到 asyncio 是有意义的。被用来同时处理 I/O 操作和网络,而不是通常的同步 python 代码。

另一件需要注意的是:如果 callee等待协程,而协程又等待 asyncio.Future , asyncio.sleep() ,或另一个在链中等待其中一件事情的协程。当阻塞 Awaitable 时,流控制将返回到事件循环。正在等待。所以以下也有效。
async def callee2():
await inner_callee()
print(f"sync called at {time.strftime('%X')}")

async def inner_callee():
await asyncio.sleep(1)

关于python - await 是否总是让其他任务有机会执行?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59996493/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com