Python 3.x 有效地使用多个异步IO队列
我目前正在构建一个项目,该项目需要向各个端点发出多个请求。我将这些请求包装在Aiohttp中,以允许异步 问题:Python 3.x 有效地使用多个异步IO队列,python-3.x,python-asyncio,aiohttp,Python 3.x,Python Asyncio,Aiohttp,我目前正在构建一个项目,该项目需要向各个端点发出多个请求。我将这些请求包装在Aiohttp中,以允许异步 问题: 我有三个队列:queue1、queue2和queue3。此外,我还有三个工作函数(worker1、worker2、worker3)与它们各自的队列相关联。第一个队列立即填充运行前已知的列表ID。当请求完成并将数据提交到数据库时,它将ID传递到queue2。worker2将获取此ID并请求更多数据。它将从该数据开始生成ID列表(不同于queue1/queue2中的IDworker2将I
我有三个队列:
queue1
、queue2
和queue3
。此外,我还有三个工作函数(worker1
、worker2
、worker3
)与它们各自的队列相关联。第一个队列立即填充运行前已知的列表ID。当请求完成并将数据提交到数据库时,它将ID传递到queue2
。worker2
将获取此ID并请求更多数据。它将从该数据开始生成ID列表(不同于queue1/queue2
中的IDworker2
将ID放入queue3
。最后worker3
将从queue3
中获取该ID,并在提交到数据库之前请求更多数据
问题在于queue.join()
是一个阻塞调用。每个工作进程都绑定到一个单独的队列,因此queue1
的连接将阻塞,直到其完成。这很好,但它也违背了使用异步的目的。不使用join()
程序无法检测队列何时完全为空。另一个问题是,当其中一个队列为空,但仍有尚未添加的数据时,可能会出现无声错误
基本代码大纲如下:
queue1=asyncio.Queue()
queue2=asyncio.Queue()
queue3=asyncio.Queue()
与aiohttp.ClientSession()作为会话异步:
对于范围(3)中的i:
tasks.append(asyncio.create_任务(worker1(queue1)))
对于范围(3)中的i:
tasks.append(asyncio.create_任务(worker2(queue2)))
对于范围(10)内的i:
tasks.append(asyncio.create_任务(worker3(queue3)))
对于ID中的i:
队列1.put_nowait(i)
等待asyncio.gather(*任务)
辅助函数位于无限循环中,等待项目进入队列
数据处理完毕后,将不会退出,程序将挂起
有没有一种方法可以有效地管理工作人员并正确结束工作?如中所述,队列。join
用于在所有注入队列的工作完成时通知制作人。因为您的第一个队列不知道某个特定项目何时完成(它被倍增并分配到其他队列),join
不是适合您的工具
从您的代码判断,您的工作人员似乎只需要运行处理队列初始项所需的时间。如果是这种情况,则可以使用关机哨兵通知工作人员退出。例如:
将aiohttp.ClientSession()作为会话进行异步:
#…如上所述创建任务。。。
对于ID中的i:
队列1.put_nowait(i)
排队1.不工作(无)#不再工作
等待asyncio.gather(*任务)
这与原始代码类似,但有明确的关闭请求。工作人员必须检测到哨兵并做出相应反应:将其传播到下一个队列/工作人员并退出。例如,在worker1
中:
为True时:
item=queue1.get()
如果项目为无:
#完成处理后,将sentinel传播到worker2并退出
等待队列2.put(无)
打破
#…像往常一样处理项目。。。
在其他两个worker中执行相同的操作(除了worker3
,它不会传播,因为没有下一个队列)一旦工作完成,将导致所有三项任务都完成。由于队列是FIFO,工人在遇到哨兵后可以安全退出,因为他们知道没有任何项目被丢弃。明确关闭还将区分关闭队列和恰好为空的队列,从而防止工人因临时事件而过早退出只有空队
这项技术实际上在队列
的文档中,但该示例有点令人困惑地显示了队列.join的使用和关机哨兵的使用。这两者是分开的,可以彼此独立使用。(同时使用它们也可能有意义,例如使用队列。加入等待“里程碑”,然后将其他东西放入队列,同时保留阻止工人的哨兵。)