【问题标题】:Is there a way to guarantee that coroutines have been started before doing something that will allow them to finish?有没有办法保证协同程序在做一些可以完成的事情之前已经启动?
【发布时间】:2023-03-15 18:04:01
【问题描述】:

我有一个方法,它使用传递给它的 ID 从 API 获取一些数据。在此之前,ID 被放置在一个队列中,以便每个 API 调用可以使用多个(最多 100 个)。 API 调用由一个名为flush_queue 的方法执行,必须在我的程序结束时调用该方法,以保证所有添加到队列中的 ID 都已被使用。我写了一个异步函数,它接受一个 ID,创建一个 flush_queue 最终设置结果的未来,然后在可用时返回为该 ID 获得的数据:

async def get_data(self, id):
    self.queued_ids.append(id)
    self.results[id] = asyncio.get_running_loop().create_future()

    if len(self.queued_ids) == 100:
        await self.flush_queue()

    return await self.results[id]

(创建并放置在results dict中的future将从flush_queue设置的该ID对应的API获取的数据作为其结果,以便可以通过上述方法返回数据。)这个在队列被刷新的情况下效果很好,因为有足够的 ID 来发出 API 请求;问题是,我需要确保在程序完成时调用flush_queue 之前将每个用户ID 添加到队列中。因此,在我这样做之前,我需要开始对get_data 的每次调用;但是,我不能等待每次调用返回的每个协程对象都完成,因为它们要等到 flush_queue 完成后才会完成。有什么办法可以确保一系列协程已经启动(但不一定完成),然后再进行调用flush_queue之类的操作?

【问题讨论】:

  • 我把你的文章读了两遍,仍然不清楚你在找什么。首先,你为什么要用你已经拥有的身份创造一个未来?其次,虽然你的代码没有说明,但我猜flush_queue是使用队列中的所有项目,但你不知道是否还有更多的项目要添加。对吗?
  • @AbhijitSarkar 我正在创建一个future,因为当调用flush_queue并获得API调用的结果时,它会找到与每个ID对应的future并使用从API获取的数据调用set_result所以它可以由 get_data 返回。 flush_queue 是使用队列中的所有项目,但是当我在程序结束时调用它以确保在程序完成之前将使用所有当前排队的项目时,我知道没有更多的项目要添加。
  • 虽然创建 id 的 future 似乎没有必要,但除此之外,你能不能一输入 get_data 就增加一个计数器并等待它变为零?基本上,使用计数信号量。
  • @AbhijitSarkar 我很好奇,当从 API 获得的数据一次传入 100 个 id 时,您将如何发回这些数据。也就是说,计数信号量的想法是完美的,我可以简单地暂停我的主程序,直到 get_data 被输入了它被调用的次数,谢谢!
  • 如何发回从 API 获得的数据 我们不要把这个问题混为一谈。如果您愿意,您可以就此提出一个新问题。我将在此处发布我之前的评论作为您的答案。

标签: python async-await python-asyncio


【解决方案1】:

正如 cmets 中所讨论的,只需使用倒计时锁存器/计数信号量即可。当你输入get_data 时增加计数器,并等待它变为零。

【讨论】:

  • asyncio 有倒计时锁吗?线程模块为此目的有一个barrier,但我不知道等效的异步原语。
  • @user4815162342 我对 Python asyncio 不是很熟悉,我指的是构造,而不是任何实际的类。快速搜索后,this 成为热门搜索,还有其他。
  • 请注意,该问题及其答案涉及线程,这会阻塞异步。 (另外,Python 已经有threading.Barrier 在之前的评论中提到过。)我知道原理是一样的,但是实现细节可能会有很大的不同。 asyncio Lock 实现与 threading.Lock 完全不同,尽管它们在抽象级别上完全相同。
  • @user4815162342 如果你想写一个实现,我会很感兴趣。如果 OP 自己还没有实施,也许 OP 会改变他对更实际的答案的接受。
  • 我现在不需要,但如果我写一个,我会在这里添加以供将来参考。我只是想知道你是否碰巧知道一个,因为我在任何地方都没有看到它,而且它时不时地出现在像这样的问题中。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-08-15
  • 2022-08-23
  • 1970-01-01
  • 1970-01-01
  • 2022-01-10
相关资源
最近更新 更多