【问题标题】:Making asyncio gather wait until all tasks are done让 asyncio 聚集等到所有任务完成
【发布时间】:2021-09-30 22:25:08
【问题描述】:

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

问题是,一项任务(据我所知)先于另一项完成,导致 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

我哪里错了?我知道我应该以某种方式让它等待所有任务完成,然后再对结果进行操作,但是在摆弄了一段时间之后,我真的不知道如何实现这一点。

【问题讨论】:

    标签: python python-asyncio


    【解决方案1】:

    您不需要以不同的方式gather 他们。你用asyncio的方式没问题。

    在您的 task 协程中删除 while 并仅附加到 results 一次。您会看到这两个任务都会返回它们的输出。

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

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

    如果你想异步运行while循环,你需要在你的task函数中为它和await创建额外的异步逻辑。

    编辑: 例如,如果您只想将其放回事件循环并允许执行其他操作,只需将 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(0.000000001)
        return results
    

    改进空间:

    • asyncio.run(main() 负责创建事件循环
    • 追加到列表是一项昂贵的操作,请尝试循环使用+= 1,这样您的results 开头将是0,然后打印结果,而不是它们的长度

    【讨论】:

    • 啊,太好了,谢谢。我以为我走在正确的轨道上。不过,还有一个问题。这应该是读取物联网设备传感器的程序的一部分。来自每个传感器的数据量各不相同,例如,一个传感器每秒可以提供 10,000 个读数,而一个传感器只能提供 2,000 个读数。现在,当我运行这个程序时,所有传感器都提供大约等量的东西。为什么会这样,有什么办法可以解决这个问题吗?我对目前获得的数据量感到非常满意,但假设我是否需要这些数据。
    • @user3553653 嘿,没问题。不确定我是否关注你,但你 await 在“内部协程”中的方式有​​时可能会很棘手。尽量不要使用await asyncio.sleep,即使它对你有用,因为你真的不需要睡觉。从字面上看,围绕执行小任务创建逻辑。一旦完成最小的一块,就把它交还给循环。如果所有任务或多或少同时休眠一秒钟,那么一秒钟内什么也没有发生。您希望一个接一个地使用任务。 Asyncio 是一种不同的思维方式。祝你好运!
    • 啊,是的,现在我想到了这个愚蠢的问题。显然,我应该让它“泵送数据”并从我想要的任何时期以任何分辨率获取它。谢谢。
    猜你喜欢
    • 2021-07-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-13
    • 2020-01-17
    • 1970-01-01
    • 1970-01-01
    • 2021-05-04
    相关资源
    最近更新 更多