我正在编写一个Python程序,该程序可以计划要发生的许多异步,受I / O约束的项目,其中许多也将计划其他类似的工作项目。这些工作项本身是完全相互独立的,它们不需要彼此的结果都完整,也不需要从它们那里收集任何结果以进行任何本地输出(除了日志记录之外,它是日志记录的一部分)工作项本身。
我最初使用的是这样的模式:
type step struct {
i int
j int
}
type steps []step
steps = append(steps, step{3, 4}, step{5, 6})
但是,我遇到了一些嵌套的async def some_task(foo):
pending = []
for x in foo:
# ... do some work ...
if some_condition:
pending.append(some_task(bar))
if pending:
await asyncio.wait(pending)
调用有时会永远挂起的麻烦,尽管asyncio.wait(pending)
的单个操作总是可以完成的(根据调试时产生的调试输出)我使用await
列出了未收集结果的状态,该结果显示所有期货都处于KeyboardInterrupt
状态。当我向其他人寻求帮助时,他们说我应该改用done
,但我没有找到任何有关如何执行此操作的有用信息,也无法从提出此建议的人那里得到澄清。
那么,我怎么满足这个用例?
答案 0 :(得分:3)
Python asyncio.Queue可能有助于将程序处理与程序完成联系起来。它具有join()
方法,该方法将一直阻塞,直到队列中的所有项目都已收到并处理为止。
我喜欢的另一个好处是,工人从队列处理中拉出来时变得更加明确,可能添加了更多项目,然后添加了ACKS,但这只是个人喜好。
async def worker(q):
while True:
item = await queue.get()
# process item potentially requeue more work
if some_condition:
await q.put('something new')
queue.task_done()
async def run():
queue = asyncio.Queue()
worker = asyncio.ensure_future(worker(queue))
await queue.join()
worker.cancel()
loop = asyncio.get_event_loop()
loop.run_until_complete(run())
loop.close()
上面的示例改编自asyncio producer_consumer示例,并进行了修改,因为您的工作人员都消费和生产:
https://asyncio.readthedocs.io/en/latest/producer_consumer.html
我不太确定如何解决您的特定示例,但我想看看asyncio提供的原语来帮助事件循环挂接到程序状态,尤其是join
并使用{{1} }。