gpt4 book ai didi

python - 在异步任务之间自由切换的正确方法是什么?

转载 作者:行者123 更新时间:2023-11-30 22:08:17 26 4
gpt4 key购买 nike

假设我有一些异步运行的任务。它们可能是完全独立的,但我仍然想设置任务暂停的点,以便它们可以同时运行。

并发运行任务的正确方法是什么?我目前正在使用 await asyncio.sleep(0),但我觉得这会增加很多开销。

import asyncio

async def do(name, amount):
for i in range(amount):
# Do some time-expensive work
print(f'{name}: has done {i}')

await asyncio.sleep(0)

return f'{name}: done'

async def main():
res = await asyncio.gather(do('Task1', 3), do('Task2', 2))
print(*res, sep='\n')

loop = asyncio.get_event_loop()

loop.run_until_complete(main())

输出

Task1: has done 0
Task2: has done 0
Task1: has done 1
Task2: has done 1
Task1: has done 2
Task1: done
Task2: done

如果我们使用简单的生成器,空的 yield 将暂停任务流程,而不会产生任何开销,但空的 await 无效。

在没有开销的情况下设置此类断点的正确方法是什么?

最佳答案

正如评论中提到的,通常 asyncio 协程会在等效同步代码中阻塞或休眠的调用上自动挂起。在您的情况下,协程是受 CPU 限制的,因此等待阻塞调用是不够的,它需要偶尔放弃对事件循环的控制以允许系统的其余部分运行。

显式 yield 在协作多任务处理中并不罕见,为此目的使用 await asyncio.sleep(0)work as intended ,它确实存在风险: sleep 太频繁,并且由于不必要的切换而减慢了计算速度; sleep 太少,并且您在单个协程中花费太多时间,从而占用了事件循环。

asyncio 提供的解决方案是使用 run_in_executor 将 CPU 密集型代码卸载到线程池。 。等待它会自动挂起协程,直到 CPU 密集型任务完成,无需任何中间轮询。例如:

import asyncio

def do(id, amount):
for i in range(amount):
# Do some time-expensive work
print(f'{id}: has done {i}')

return f'{id}: done'

async def main():
loop = asyncio.get_event_loop()
res = await asyncio.gather(
loop.run_in_executor(None, do, 'Task1', 5),
loop.run_in_executor(None, do, 'Task2', 3))
print(*res, sep='\n')

loop = asyncio.get_event_loop()
loop.run_until_complete(main())

关于python - 在异步任务之间自由切换的正确方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52209274/

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