Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/python-3.x/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 3.x 有效地使用多个异步IO队列_Python 3.x_Python Asyncio_Aiohttp - Fatal编程技术网

Python 3.x 有效地使用多个异步IO队列

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

我目前正在构建一个项目,该项目需要向各个端点发出多个请求。我将这些请求包装在Aiohttp中,以允许异步

问题:
我有三个队列:
queue1
queue2
queue3
。此外,我还有三个工作函数(
worker1
worker2
worker3
)与它们各自的队列相关联。第一个队列立即填充运行前已知的列表ID。当请求完成并将数据提交到数据库时,它将ID传递到
queue2
worker2
将获取此ID并请求更多数据。它将从该数据开始生成ID列表(不同于
queue1/queue2
中的ID
worker2
将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的使用和关机哨兵的使用。这两者是分开的,可以彼此独立使用。(同时使用它们也可能有意义,例如使用
队列。加入
等待“里程碑”,然后将其他东西放入队列,同时保留阻止工人的哨兵。)