我很好奇是否有办法手动锁定multiprocessing.Queue
对象。
我有一个非常标准的生产者/消费者模式设置,其中我的主线程不断产生一系列值,并且multiprocessing.Process
工作池正在对生成的值进行操作。
全部通过鞋底multiprocessing.Queue()
控制。
import time
import multiprocessing
class Reader(multiprocessing.Process):
def __init__(self, queue):
multiprocessing.Process.__init__(self)
self.queue = queue
def run(self):
while True:
item = self.queue.get()
if isinstance(item, str):
break
if __name__ == '__main__':
queue = multiprocessing.Queue()
reader = Reader(queue)
reader.start()
start_time = time.time()
while time.time() - start_time < 10:
queue.put(1)
queue.put('bla bla bla sentinal')
queue.join()
我遇到的问题是我的工作池不能像主线程插入值一样快地消耗和处理queue
。所以在一段时间之后,Queue是如此笨重,以至于它会弹出一个MemoryError。
一个明显的解决方案是简单地在生产者中添加一个等待检查,以阻止它将更多的值放入队列。有点像:
while time.time() - start_time < 10:
queue.put(1)
while queue.qsize() > some_size:
time.sleep(.1)
queue.put('bla bla bla sentinal')
queue.join()
但是,由于程序的时髦性,我想将队列中的所有内容转储到文件中以供以后处理。但!无法暂时锁定队列,工作人员无法消耗其中的所有内容,因为生产者不断用垃圾填充它 - 无论如何。经过多次测试后,似乎在某个时刻其中一个锁获胜(但通常会添加到队列中)。
编辑:此外,我意识到可以简单地停止制作人并从该线程中消费它......但这让我的单一责任人感到难过,因为制作人是制片人,而不是消费者。
在浏览Queue
的来源后,我想出了这个:
def dump_queue(q):
q._rlock.acquire()
try:
res = []
while not q.empty():
res.append(q._recv())
q._sem.release()
return res
finally:
q._rlock.release()
但是,我太害怕了!我不知道这是否“正确”。我没有足够的把握知道这是否会在没有炸毁Queue
内部任何内容的情况下保持这种状态。
任何人都知道这会不会破裂? :)
答案 0 :(得分:2)
鉴于评论中的内容,Queue
对于您的问题来说只是一个错误的数据结构 - 但很可能是部分的可用解决方案。
听起来你只有一个制片人。创建一个新的,生产者本地(不跨进程共享)类,实现您真正需要的语义。例如,
class FlushingQueue:
def __init__(self, mpqueue, path_to_spill_file, maxsize=1000, dumpsize=1000000):
from collections import deque
self.q = mpqueue # a shared `multiprocessing.Queue`
self.dump_path = path_to_spill_file
self.maxsize = maxsize
self.dumpsize = dumpsize
self.d = deque() # buffer for overflowing values
def put(self, item):
if self.q.qsize() < self.maxsize:
self.q.put(item)
# in case consumers have made real progress
while self.d and self.q.qsize() < self.maxsize:
self.q.put(self.d.popleft())
else:
self.d.append(item)
if len(self.d) >= self.dumpsize:
self.dump()
def dump(self):
# code to flush self.d to the spill file; no
# need to look at self.q at all
我打赌你能做到这一点: - )