在 asyncio 中检索任务结果的正确方法
Proper way to retrieve the result of tasks in asyncio
我正在尝试检查 asyncio 模块的 wait
方法。我有这个原始的测试应用程序作为游乐场:
import asyncio
async def foo():
return 1 # datetime.datetime.now()
async def entry_point():
coros = [foo()]*3
done, pending = await asyncio.wait(coros, return_when=asyncio.FIRST_COMPLETED)
for obj in done:
print(obj._result) # works, but seem dirty
asyncio.run(entry_point())
基本上,我的目标是获得第一个完成任务的结果。在这里,我对术语有点困惑。文档说 asyncio.wait
Returns two sets of Tasks/Futures: (done, pending).
我如何知道对象是 task
还是 future
?
主要问题是,如何提取成功结束任务的结果?
一种方法是访问受保护的属性 _result
(如我的代码片段所示)。但我觉得有一种更简洁的方法可以做到这一点。实现该目标的正确模式是什么?
https://docs.python.org/3/library/asyncio-task.html#waiting-primitives
asyncio.wait 的文档有以下注释:
Deprecated since version 3.8, will be removed in version 3.11: Passing
coroutine objects to wait() directly is deprecated.
因此你应该使用asyncio.Task that also has the asyncio.Task.result方法:
test.py:
import asyncio
import random
async def task(i):
t = random.uniform(1, 5)
print(f"START: {i} ({t:.3f}s)")
await asyncio.sleep(t)
print(f"END: {i}")
return i
async def main():
tasks = []
for i in range(5):
tasks.append(asyncio.create_task(task(i)))
done, pending = await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED)
for t in done:
print(t.result())
if __name__ == "__main__":
asyncio.run(main())
测试:
$ python test.py
START: 0 (2.743s)
START: 1 (2.490s)
START: 2 (4.785s)
START: 3 (3.746s)
START: 4 (1.010s)
END: 4
4
如果您想检索所有结果并首先获取最早的下一个结果,请改用asyncio.as_completed:
...
for t in asyncio.as_completed(tasks):
print(await t)
...
测试 2:
$ python test.py
START: 0 (2.155s)
START: 1 (1.309s)
START: 2 (3.380s)
START: 3 (3.451s)
START: 4 (1.587s)
END: 1
1
END: 4
4
END: 0
0
END: 2
2
END: 3
3
我正在尝试检查 asyncio 模块的 wait
方法。我有这个原始的测试应用程序作为游乐场:
import asyncio
async def foo():
return 1 # datetime.datetime.now()
async def entry_point():
coros = [foo()]*3
done, pending = await asyncio.wait(coros, return_when=asyncio.FIRST_COMPLETED)
for obj in done:
print(obj._result) # works, but seem dirty
asyncio.run(entry_point())
基本上,我的目标是获得第一个完成任务的结果。在这里,我对术语有点困惑。文档说 asyncio.wait
Returns two sets of Tasks/Futures: (done, pending).
我如何知道对象是 task
还是 future
?
主要问题是,如何提取成功结束任务的结果?
一种方法是访问受保护的属性 _result
(如我的代码片段所示)。但我觉得有一种更简洁的方法可以做到这一点。实现该目标的正确模式是什么?
https://docs.python.org/3/library/asyncio-task.html#waiting-primitives
asyncio.wait 的文档有以下注释:
Deprecated since version 3.8, will be removed in version 3.11: Passing coroutine objects to wait() directly is deprecated.
因此你应该使用asyncio.Task that also has the asyncio.Task.result方法:
test.py:
import asyncio
import random
async def task(i):
t = random.uniform(1, 5)
print(f"START: {i} ({t:.3f}s)")
await asyncio.sleep(t)
print(f"END: {i}")
return i
async def main():
tasks = []
for i in range(5):
tasks.append(asyncio.create_task(task(i)))
done, pending = await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED)
for t in done:
print(t.result())
if __name__ == "__main__":
asyncio.run(main())
测试:
$ python test.py
START: 0 (2.743s)
START: 1 (2.490s)
START: 2 (4.785s)
START: 3 (3.746s)
START: 4 (1.010s)
END: 4
4
如果您想检索所有结果并首先获取最早的下一个结果,请改用asyncio.as_completed:
...
for t in asyncio.as_completed(tasks):
print(await t)
...
测试 2:
$ python test.py
START: 0 (2.155s)
START: 1 (1.309s)
START: 2 (3.380s)
START: 3 (3.451s)
START: 4 (1.587s)
END: 1
1
END: 4
4
END: 0
0
END: 2
2
END: 3
3