是否有人知道从multiprocessing.Queue
获得接近LIFO甚至不接近FIFO(例如随机)行为的干净方法?
备选问题:有人可以指出管理multiprocessing.Queue
背后实际存储结构的线程的代码吗?似乎提供近似LIFO访问权限的内容似乎很简单但是我迷失在试图找到它的兔子洞里。
注意:
multiprocessing.Queue
does not guarantee order。精细。但它接近FIFO,所以接近LIFO会很棒。(编辑)澄清:我正在使用multiprocessing
进行CPU绑定模拟,因此无法使用Queue
中的专用队列。由于我几天没有看到任何答案,我已经在上面添加了替代问题。
如果是一个问题,下面是multiprocessing.Queue
接近FIFO的轻微证据。它只是表明在一个简单的情况下(单个线程),它在我的系统上是完美的FIFO:
import multiprocessing as mp
import Queue
q = mp.Queue()
for i in xrange(1000):
q.put(i)
deltas = []
while True:
try:
value1 = q.get(timeout=0.1)
value2 = q.get(timeout=0.1)
deltas.append(value2-value1)
except Queue.Empty:
break
#positive deltas would indicate the numbers are coming out in increasing order
min_delta, max_delta = min(deltas), max(deltas)
avg_delta = sum(deltas)/len(deltas)
print "min", min_delta
print "max", max_delta
print "avg", avg_delta
打印:min,max和average正好为1(完美FIFO)
答案 0 :(得分:2)
我查看了我的Python安装中的Lib/multiprocessing/queues.py
中的Queue类(Python 2.7,但是我简要检查过的Python 3.2版本没有任何明显的不同)。以下是我理解它的工作原理:
Queue对象维护有两组对象。一组是由所有进程共享的多进程安全原型。其他过程由每个过程单独创建和使用。
跨进程对象在__init__
方法中设置:
Pipe
个对象,其两端保存为self._reader
和self._writer
。BoundedSemaphore
对象,它计算(并可选地限制)队列中有多少个对象。Lock
对象,在非Windows平台上用于写入管道。 (我认为这是因为在Windows上写入管道本质上是多进程安全的。)每个进程对象在_after_fork
和_start_thread
方法中设置:
collections.deque
对象。threading.condition
对象。threading.Thread
对象。它是懒惰创建的,因此在给定进程中至少要求对Queue进行一次写入之前它不会存在。Finalize
个对象。队列中的get
非常简单。您获取读锁定,递减信号量,并从管道的读取端抓取一个对象。
put
更复杂。它使用多个线程。 put
的调用者获取条件的锁定,然后将其对象添加到缓冲区并在解锁之前发出信号。它还会增加信号量并启动编写器线程(如果它还没有运行)。
编写器线程在_feed
方法中永远循环(直到取消)。如果缓冲区为空,则等待notempty
条件。然后它从缓冲区获取一个项目,获取写锁定(如果存在)并将该项目写入管道。
所以,鉴于所有这些,您可以修改它以获得LIFO队列吗?这看起来并不容易。管道本质上是FIFO对象,虽然队列不能保证整体的FIFO行为(由于来自多个进程的写入的异步性质),但它总是主要是FIFO。
如果您只有一个使用者,则可以从队列中get
个对象并将它们添加到您自己的进程本地堆栈中。使用多用户堆栈会更难,但是对于共享内存,有限大小的堆栈也不会太难。您需要一个锁,一对条件(用于在完全和空状态下阻塞/发信号),共享整数值(对于保持的值的数量)和适当类型的共享数组(对于值本身)。
答案 1 :(得分:1)
Queue包中有LIFO queue(Python 3中的队列)。这不会在多处理或multiprocessing.queues模块中公开。
用q = mp.Queue()
替换你的行q = Queue.LifoQueue()
并运行print:min,max和average正好为-1。
(另外我认为在从一个线程获取项目时,您应该始终获得完全FIFO / LIFO顺序。)