我有一个简单的任务:
def worker(queue):
while True:
try:
_ = queue.get_nowait()
except Queue.Empty:
break
if __name__ == '__main__':
manager = multiprocessing.Manager()
# queue = multiprocessing.Queue()
queue = manager.Queue()
for i in range(5):
queue.put(i)
processes = []
for i in range(2):
proc = multiprocessing.Process(target=worker, args=(queue,))
processes.append(proc)
proc.start()
for proc in processes:
proc.join()
似乎多处理。队列可以完成我需要的所有工作,但另一方面,我看到很多 manager() 的例子。队列()并且无法理解我真正需要什么。看起来像经理()。Queue() 使用某种代理对象,但我不明白这些目的,因为多处理。Queue() 在没有任何代理对象的情况下执行相同的工作。
所以,我的问题是:
1)多处理之间的真正区别是什么。multiprocessing.manager() 返回的队列和对象。队列()?
2) 我需要使用什么?
虽然我对这个主题的理解有限,但从我所做的工作来看,多处理之间有一个主要区别。队列() 和多处理。经理()。队列():
- 多处理。Queue() 是一个对象,而多处理。经理()。Queue() 是指向由多处理管理的共享队列的地址(代理)。管理器() 对象。
- 因此,您无法通过正常的多处理。Queue() 对象到池方法,因为它不能被酸洗。
- 此外,python文档告诉我们在使用多处理时要特别注意。Queue(),因为它可能会产生不良影响
放入队列时,将酸洗该对象,稍后后台线程会将酸洗的数据刷新到基础管道。这会产生一些令人惊讶的后果,但应该不会造成任何实际困难——如果它们真的困扰你,那么你可以改用经理创建的队列。 将对象放在空队列中后,在队列的 empty() 方法返回 False 之前可能会有无穷小的延迟,并且 get_nowait() 可以在不引发 Queue.Empty 的情况下返回。 如果多个进程正在对对象进行排队,则可能会在另一端无序接收对象。但是,由同一进程排队的对象将始终按彼此的预期顺序排列。
警告如上所述,如果子进程已将项目放入队列(并且未使用 JoinableQueue.cancel_join_thread),则在所有缓冲项目刷新到管道之前,该进程不会终止。 这意味着,如果您尝试加入该进程,除非您确定已放入队列中的所有项目都已使用,否则可能会遇到死锁。同样,如果子进程是非守护进程,则父进程在尝试加入其所有非守护进程子进程时可能会在退出时挂起。 请注意,使用管理器创建的队列不存在此问题。
有一种使用多处理的解决方法。Queue() 与 Pool 通过将队列设置为全局变量并在初始化时为所有进程设置它:
queue = multiprocessing.Queue()
def initialize_shared(q):
global queue
queue=q
pool= Pool(nb_process,initializer=initialize_shared, initargs(queue,))
将创建具有正确共享队列的池进程,但我们可以争辩说是多处理。队列() 对象不是为此用途而创建的。
另一方面是经理。Queue() 可以通过将其作为函数的普通参数传递来在池子进程之间共享。
在我看来,使用多处理。经理()。Queue() 在每种情况下都很好,而且不那么麻烦。使用管理器可能会有一些缺点,但我不知道。
我最近遇到了一个Manager().Queue()
问题,当SyncManager
对象 - 由multiprocessing.Manager()
返回 - 似乎死亡,并且它管理的队列永远阻塞(即使有*_nowait()
)。
我不确定原因,或者如果 SyncManager 真的死了,我唯一的线索是我从一个类实例调用multiprocessing.Manager()
,该类实例具有__del__()
,它记录了调用它的进程,我可以看到这是从 SyncManager 进程中__del__()
调用的。
这意味着我的对象在 SyncManager 进程中有一个副本,并且它被垃圾回收。这可能意味着只有我的对象被删除了,并且 SyncManager 很好,但我确实看到相应的队列变得无响应与 SyncManager 进程中的__del__()
调用相关。
我不知道我的对象是如何在 SyncManager 进程中结束的。我通常会抽出 50-200 名经理——有些生命周期重叠,有些则没有——直到我看到这个问题。对于解释器退出时存在的对象,不会调用__del__()
,我通常不会看到 SyncManager 对象从__del__()
中被此日志死亡,只是偶尔。可能当出现问题时,SyncManager 对象首先释放其对象,然后解释器才会退出,这就是为什么我偶尔会看到__del__()
调用的原因。
我确实看到我的队列变得无响应,即使在我没有看到从 SyncManager 调用__del__()
的情况下也是如此。
我也看到SyncManager"死亡"而没有引起进一步的问题。
我所说的"无响应"是指:
queue.get(timeout=1)
queue.put(timeout=1)
再也不回来了。
queue.get_nowait(timeout=1)
queue.put_nowait(timeout=1)
再也不回来了。
这变得有点复杂,然后我原本想要,但我让细节进来,以防万一它对某人有帮助。
我以前用了很长时间Manager().Queue()
,没有任何问题。我怀疑实例化大量管理器对象导致了问题,或者实例化了大量管理器导致了一直存在的问题。
我用Python 3.6.5
.