在我的一个宠物项目中,我使用了
根据我将通过
那么问题是:为什么第三种情况会导致
更新,试图澄清问题:在第3种情况下(
更新2:使示例更类似于我实际在代码中所做的事情
multiprocessing
模块进行同时下载。在使用multiprocessing.Manager()
对象生成的Queue
对象时,我遇到了一种奇怪的行为。根据我将通过
Manager
生成的Queue对象放置在另一个Queue
对象(也是通过Manager
生成)内的方式,我会得到不同的行为,但在我看来,这两种方式本质上是相同的。以下是一个最小化的示例:import multiprocessing
import Queue
def work(inbound_queue, keep_going):
while keep_going.value == 1:
try:
outbound_queue = inbound_queue.get(False) # this fails in case 3
#do some work
outbound_queue.put("work done!")
except Queue.Empty:
pass #this is busy wait of course, it's just an example
class Weird:
def __init__(self):
self.manager = multiprocessing.Manager()
self.queue = self.manager.Queue()
self.keep_going = multiprocessing.Value("i", 1)
self.worker = multiprocessing.Process(target = work, args = (self.queue, self.keep_going))
self.worker.start()
def stop(self): #close and join the second process
self.keep_going.value = 0
self.worker.join()
def queueFromOutside(self, q):
self.queue.put(q)
return q
def queueFromNewManager(self):
q = multiprocessing.Manager().Queue()
self.queue.put(q)
return q
def queueFromOwnManager(self):
q = self.manager.Queue()
self.queue.put(q)
return q
if __name__ == '__main__':
instance = Weird()
# CASE 1
queue = multiprocessing.Manager().Queue()
q1 = instance.queueFromOutside(queue) # Works fine
print "1: ", q1.get()
# CASE 2
q2 = instance.queueFromNewManager() # Works fine
print "2: ", q2.get()
# CASE 3
q3 = instance.queueFromOwnManager() # Error
print "3: ", q3.get()
instance.stop() #sadly never called :(
并输出(Python 2.7.10 x86,Windows)。
主要输出:
1: work done!
2: work done!
3:
如果工作进程崩溃,则会导致q3.get()挂起。
工作进程的输出:
Process Process-2:
Traceback (most recent call last):
File "C:\Python27\lib\multiprocessing\process.py", line 258, in _bootstrap
self.run()
File "C:\Python27\lib\multiprocessing\process.py", line 114, in run
self._target(*self._args, **self._kwargs)
File "J:\Dropbox\Python\queues2.py", line 7, in work
outbound_queue = inbound_queue.get(False) # this fails in case 3
File "<string>", line 2, in get
File "C:\Python27\lib\multiprocessing\managers.py", line 774, in _callmethod
raise convert_to_error(kind, result)
RemoteError:
---------------------------------------------------------------------------
Unserializable message: ('#RETURN', <Queue.Queue instance at 0x025A22B0>)
---------------------------------------------------------------------------
那么问题是:为什么第三种情况会导致
RemoteError
?提供的示例与实际项目中的代码结构不太相似,但如果我使用方法1和2发送队列到运行中的进程,则可以正常工作。使用方法3会很好,因为它可以节省每次获取Manager
的麻烦,这可能需要很长时间(在我现在使用的机器上大约100毫秒)。这个问题出于好奇,因为我仍在学习模块中所有酷炫的东西。更新,试图澄清问题:在第3种情况下(
queueFromOwnManager
),为什么self.manager.Queue()
创建的队列一旦放入self.queue
中,就不能使用self.queue.get()
检索,而使用multiprocessing.Manager().Queue()
创建的队列可以检索?执行3种情况的顺序无关紧要。理想情况下,在3个示例中的任何一个方法调用之前和之后,instance.queue
都将为空。更新2:使示例更类似于我实际在代码中所做的事情