考虑以下代码:
import asyncio
async def subsubfunc():
print(" subsubfunc")
# [some async I/O code here]
async def subfunc():
print(" subfunc A")
awaitable = subsubfunc()
print(" subfunc B")
await awaitable
print(" subfunc C")
async def func():
print("func A")
awaitable = subfunc()
print("func B")
await awaitable
print("func C")
asyncio.run(func())
实际产量:
func A
func B
subfunc A
subfunc B
subsubfunc
subfunc C
func C
所需输出:
func A
subfunc A
subsubfunc
subfunc B
subfunc C
func B
func C
更准确地说,我希望所有无法急切完成的工作都能够真正急切完成(在调用者继续执行之前)。
以下代码片段以一种相当黑客的方式模拟了这一点:
import asyncio
async def subsubfunc():
print(" subsubfunc")
# [some async I/O code here]
async def subfunc():
print(" subfunc A")
awaitable = asyncio.create_task(subsubfunc())
await asyncio.sleep(0)
print(" subfunc B")
await awaitable
print(" subfunc C")
async def func():
print("func A")
awaitable = asyncio.create_task(subfunc())
await asyncio.sleep(0) # subfunc is started here
await asyncio.sleep(0) # subsubfunc is started here
print("func B")
await awaitable
print("func C")
asyncio.run(func())
有没有更干净的方法来做到这一点?
编辑:澄清一下:我希望
func B
和subfunc B
在协程完成之前打印。想象一下 [some async I/O code here]
等待 I/O。调用者应在 I/O 完成之前继续。一个可能的用例是,如果数据可以(并且必须)以非阻塞方式发送,然后同一个协程需要等待响应,并且在调用者之间应该执行额外的工作。
awaitable = subsubfunc()
...然后你说...
await awaitable
...这两个语句相当于单个语句:
await subsubfunc()
请注意,语句 awaitable = subsubfunc()
不会导致任何内容运行。只有当您
await
异步函数调用(或对此类函数调用的引用,例如变量
awaitable
)时,某些内容才会运行。所以你只需要移动几个
await
语句:
import asyncio
async def subsubfunc():
print(" subsubfunc")
# [some async I/O code here]
async def subfunc():
print(" subfunc A")
awaitable = subsubfunc()
await awaitable
print(" subfunc B")
print(" subfunc C")
async def func():
print("func A")
awaitable = subfunc()
await awaitable
print("func B")
print("func C")
asyncio.run(func())
可以简化为:
import asyncio
async def subsubfunc():
print(" subsubfunc")
# [some async I/O code here]
async def subfunc():
print(" subfunc A")
await subsubfunc()
print(" subfunc B")
print(" subfunc C")
async def func():
print("func A")
await subfunc()
print("func B")
print("func C")
asyncio.run(func())
打印:
func A
subfunc A
subsubfunc
subfunc B
subfunc C
func B
func C
asyncio.sleep
asyncio.eager_task_factory
即可实现此目的
使用此工厂时,协程在任务构造期间开始同步执行。仅当任务阻塞时,才会在事件循环上安排任务。
import asyncio
async def subsubfunc():
print(" subsubfunc")
# [some async I/O code here]
async def subfunc():
print(" subfunc A")
awaitable = asyncio.create_task(subsubfunc())
print(" subfunc B")
await awaitable
print(" subfunc C")
async def func():
print("func A")
awaitable = asyncio.create_task(subfunc())
print("func B")
await awaitable
print("func C")
loop = asyncio.new_event_loop()
loop.set_task_factory(asyncio.eager_task_factory)
loop.run_until_complete(func())
asyncio.sleep(0)
是允许其他任务运行的有效方法,并记录在
asyncio
文档中:
sleep() 总是挂起当前任务,允许其他任务运行。将延迟设置为 0 可以提供优化的路径以允许其他任务运行。长时间运行的函数可以使用它来避免在函数调用的整个持续时间内阻塞事件循环。