让异步收集等待所有任务完成

时间:2019-11-09 21:11:43

标签: python python-asyncio

我应该并行运行一些函数并收集数据一秒钟,然后在经过一段时间后返回数据。

问题是,(据我所知)一项任务在另一项之前完成,导致results在该结果上为空。下面的代码为例:

import asyncio
import time

async def task(id, end_time):
    print('Started task ', id)
    results = []
    while time.time() < end_time:
        results.append(1)
    return results


async def main():
    while True:
        end_time = time.time() + 1
        results = await asyncio.gather(*[task(i,end_time) for i in range(2)])
        print(len(results[0]), len(results[1]))
try:
    loop = asyncio.get_event_loop()
    loop.run_until_complete(main())
except KeyboardInterrupt:
    pass
finally:
    loop.close()

返回

Started task  0
Started task  1
5580452 0

我要去哪里错了?我知道我应该以某种方式使其等待所有任务完成,然后再处理结果,但是经过一段时间摆弄不同的事情之后,我真的不知道如何实现这一目标。

1 个答案:

答案 0 :(得分:2)

您不需要gather进行其他操作。您可以使用asyncio的方式。

在您的task协程中,删除while并附加到results一次。您将看到两个任务都将返回其输出。

问题在于,您执行while time.time()时会锁定它,因为它不是异步的。因此它将运行while循环,直到满足end_time条件为止。

然后第二个开始,因为task Coro不允许在此期间执行任何其他操作。由于两者都使用相同的end_time,因此第二个coro将永远不会追加。

如果要异步运行while循环,则需要为其创建附加的异步逻辑,并在await函数中task对其进行创建。

编辑: 例如,如果您只想将其放回事件循环并允许执行其他操作,只需将await asyncio.sleep(0.1)放入while循环中即可。

示例:

async def task(id, end_time):
    print('Started task ', id)
    results = []
    while time.time() < end_time:
        results.append(1)
        await asyncio.sleep(000000000.1)
    return results

有待改进的空间:
-asyncio.run(main()负责创建事件循环
-追加到列表是一项昂贵的操作,请循环尝试+= 1,这样您的results将以0开头,然后打印结果,而不是其len