我有一个很大的代码库来并行化。我可以避免使用单个全局队列重写数百个函数的方法签名。我知道它很乱;请不要告诉我,如果我使用全局变量,我在这种情况下做错了,这真的是最简单的选择。下面的代码有效,但我不明白为什么。我声明了一个全局的multiprocessing.Queue(),但是没有声明它应该在进程之间共享(通过将它作为参数传递给worker)。 python会自动将此队列放在共享内存中吗?在更大规模上这样做是否安全?
注意:您可以告诉队列在进程之间共享:工作进程在空队列上开始工作并在主队列将某些工作推送到队列之前空闲一秒钟。
import multiprocessing
import time
outqueue = None
class WorkerProcess(multiprocessing.Process):
def __init__(self):
multiprocessing.Process.__init__(self)
self.exit = multiprocessing.Event()
def doWork(self):
global outqueue
ob = outqueue.get()
ob = ob + "!"
print ob
time.sleep(1) #simulate more hard work
outqueue.put(ob)
def run(self):
while not self.exit.is_set():
self.doWork()
def shutdown(self):
self.exit.set()
if __name__ == '__main__':
global outqueue
outqueue = multiprocessing.Queue()
procs = []
for x in range(10):
procs.append(WorkerProcess())
procs[x].start()
time.sleep(1)
for x in range(20):
outqueue.put(str(x))
time.sleep(10)
for p in procs:
p.shutdown()
for p in procs:
p.join()
try:
while True:
x = outqueue.get(False)
print x
except:
print "done"
答案 0 :(得分:1)
假设您正在使用Linux,答案就在于操作系统创建新流程的方式。
当一个进程在Linux中生成一个新进程时,它实际上会分析父进程。结果是子进程具有父进程的所有属性。基本上是一个克隆。
在您的示例中,您将实例化队列,然后创建新进程。因此子进程将具有相同队列的副本,并且能够使用它。
要查看已损坏的内容,请尝试先创建进程,然后再创建Queue对象。您将看到具有全局变量的子项仍设置为None,而父项将具有队列。
在Linux上将Queue作为全局变量共享是安全的,但不建议这样做。在Windows上,由于流程创建方法不同,通过全局变量共享队列将不起作用。
中所述明确地将资源传递给子进程
在使用fork start方法的Unix上,子进程可以使用全局资源在父进程中创建的共享资源。但是,最好将对象作为参数传递给子进程的构造函数。
除了使代码(可能)与Windows和其他启动方法兼容之外,这还确保只要子进程仍处于活动状态,对象就不会在父进程中进行垃圾回收。如果在父进程中对对象进行垃圾回收时释放某些资源,这可能很重要。
有关Linux forking的更多信息,您可以阅读其man page。