在两个(多处理)Queues中的任何一个可用的情况下等待(不旋转)的最佳方式是什么,两者都位于同一系统中?
答案 0 :(得分:25)
实际上你可以在select.select中使用multiprocessing.Queue对象。即
que = multiprocessing.Queue()
(input,[],[]) = select.select([que._reader],[],[])
只有在准备好读取时才会选择que。
虽然没有关于它的文档。我正在阅读multiprocessing.queue库的源代码(在linux上它通常像/usr/lib/python2.6/multiprocessing/queue.py一样)来查找它。
使用Queue.Queue我没有找到任何聪明的方法来做到这一点(我真的很喜欢)。
答案 1 :(得分:14)
看起来还没有正式的方法来处理这个问题。或者至少,不是基于此:
您可以尝试类似这篇文章的内容 - 访问底层管道文件句柄:
然后使用select。
答案 2 :(得分:2)
似乎使用线程将传入的项目转发到单个队列,然后在以独立于平台的方式使用多处理时,等待它是一个实用的选择。
避免线程需要处理低级管道/ FD,这些管道/ FD既是平台特定的,也不容易与更高级别的API一致处理。
或者你需要能够设置回调的队列,我认为这是适当的更高级别的接口。即你会写一些类似的东西:
singlequeue = Queue() incoming_queue1.setcallback(singlequeue.put) incoming_queue2.setcallback(singlequeue.put) ... singlequeue.get()
也许多处理程序包可以增长这个API,但它还没有。这个概念适用于使用术语“频道”而不是“队列”的py.execnet,请参阅此处http://tinyurl.com/nmtr4w
答案 3 :(得分:1)
您可以使用类似Observer模式的内容,其中会向队列订阅者通知状态更改。
在这种情况下,您可以将工作线程指定为每个队列上的侦听器,并且每当它收到就绪信号时,它可以处理新项目,否则休眠。
答案 4 :(得分:1)
不确定多处理队列上的选择在Windows上的效果如何。由于Windows上的select选择侦听套接字而不是文件句柄,我怀疑可能存在问题。
我的回答是让一个线程以阻塞的方式监听每个队列,并将结果全部放入主线程监听的单个队列中,基本上将各个队列复用为一个队列。
我这样做的代码是:
"""
Allow multiple queues to be waited upon.
queue,value = multiq.select(list_of_queues)
"""
import queue
import threading
class queue_reader(threading.Thread):
def __init__(self,inq,sharedq):
threading.Thread.__init__(self)
self.inq = inq
self.sharedq = sharedq
def run(self):
while True:
data = self.inq.get()
print ("thread reads data=",data)
result = (self.inq,data)
self.sharedq.put(result)
class multi_queue(queue.Queue):
def __init__(self,list_of_queues):
queue.Queue.__init__(self)
for q in list_of_queues:
qr = queue_reader(q,self)
qr.start()
def select(list_of_queues):
outq = queue.Queue()
for q in list_of_queues:
qr = queue_reader(q,outq)
qr.start()
return outq.get()
以下测试程序显示了如何使用它:
import multiq
import queue
q1 = queue.Queue()
q2 = queue.Queue()
q3 = multiq.multi_queue([q1,q2])
q1.put(1)
q2.put(2)
q1.put(3)
q1.put(4)
res=0
while not res==4:
while not q3.empty():
res = q3.get()[1]
print ("returning result =",res)
希望这有帮助。
托尼华莱士答案 5 :(得分:1)
以上代码的新版本......
不确定多处理队列上的选择在Windows上的效果如何。由于Windows上的select选择侦听套接字而不是文件句柄,我怀疑可能存在问题。
我的回答是让一个线程以阻塞的方式监听每个队列,并将结果全部放入主线程监听的单个队列中,基本上将各个队列复用为一个队列。
我这样做的代码是:
"""
Allow multiple queues to be waited upon.
An EndOfQueueMarker marks a queue as
"all data sent on this queue".
When this marker has been accessed on
all input threads, this marker is returned
by the multi_queue.
"""
import queue
import threading
class EndOfQueueMarker:
def __str___(self):
return "End of data marker"
pass
class queue_reader(threading.Thread):
def __init__(self,inq,sharedq):
threading.Thread.__init__(self)
self.inq = inq
self.sharedq = sharedq
def run(self):
q_run = True
while q_run:
data = self.inq.get()
result = (self.inq,data)
self.sharedq.put(result)
if data is EndOfQueueMarker:
q_run = False
class multi_queue(queue.Queue):
def __init__(self,list_of_queues):
queue.Queue.__init__(self)
self.qList = list_of_queues
self.qrList = []
for q in list_of_queues:
qr = queue_reader(q,self)
qr.start()
self.qrList.append(qr)
def get(self,blocking=True,timeout=None):
res = []
while len(res)==0:
if len(self.qList)==0:
res = (self,EndOfQueueMarker)
else:
res = queue.Queue.get(self,blocking,timeout)
if res[1] is EndOfQueueMarker:
self.qList.remove(res[0])
res = []
return res
def join(self):
for qr in self.qrList:
qr.join()
def select(list_of_queues):
outq = queue.Queue()
for q in list_of_queues:
qr = queue_reader(q,outq)
qr.start()
return outq.get()
以下代码是我的测试例程,用于说明其工作原理:
import multiq
import queue
q1 = queue.Queue()
q2 = queue.Queue()
q3 = multiq.multi_queue([q1,q2])
q1.put(1)
q2.put(2)
q1.put(3)
q1.put(4)
q1.put(multiq.EndOfQueueMarker)
q2.put(multiq.EndOfQueueMarker)
res=0
have_data = True
while have_data:
res = q3.get()[1]
print ("returning result =",res)
have_data = not(res==multiq.EndOfQueueMarker)
答案 6 :(得分:0)
从Python 3.3开始,您可以使用multiprocessing.connection.wait一次等待多个Queue._reader
对象。
答案 7 :(得分:0)
我通常想要多路复用多个队列的一种情况是,每个队列对应于需要不同处理程序的不同类型的消息。你不能只从一个队列中拉取,因为如果它不是你想要的消息类型,你需要把它放回去。
然而,在这种情况下,每个处理程序本质上都是一个单独的消费者,这使得它成为一个多生产者、多消费者的问题。幸运的是,即使在这种情况下,您仍然不需要阻塞多个队列。您可以为每个处理程序创建不同的线程/进程,每个处理程序都有自己的队列。基本上,您可以将其分解为多生产者、单消费者问题的多个实例。
我能想到的唯一一种情况是,您必须在多个队列上等待,如果您被迫将多个处理程序放在同一个线程/进程中。在这种情况下,我会通过为我的主线程创建一个队列来重构它,为每个处理程序生成一个线程,并让处理程序使用主队列与主线程通信。然后,每个处理程序都可以为其独特的消息类型设置一个单独的队列。
答案 8 :(得分:-3)
不要这样做。
在邮件上放置标题并将其发送到公共队列。这简化了代码并且整体更清晰。