【问题标题】:Proper way to retrieve the result of tasks in asyncio在 asyncio 中检索任务结果的正确方法
【发布时间】:2021-09-28 04:05:55
【问题描述】:

我正在尝试检查 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

返回两组任务/未来:(完成,待定)。

我如何知道对象是task 还是future? 主要问题是,如何提取成功结束任务的结果? 一种方法是访问受保护的属性_result(如我的代码 sn-p 所示)。但我觉得有一种更清洁的方法可以做到这一点。实现这一目标的正确模式是什么?

https://docs.python.org/3/library/asyncio-task.html#waiting-primitives

【问题讨论】:

  • 您是否查看了链接中记录的FIRST_COMPLETED 选项?

标签: python-asyncio


【解决方案1】:

asyncio.wait 的文档有以下注释:

自 3.8 版起已弃用,将在 3.11 版中删除:通过 不推荐直接使用 wait() 的协程对象。

因此,您应该使用同样具有asyncio.Task.result 方法的asyncio.Task

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-07-20
    • 1970-01-01
    • 1970-01-01
    • 2015-08-25
    • 2020-08-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多