问题描述
最近在解决一个并行化的问题时,我需要在多个子进程中计算得出的numpy矩阵供主进程加起来求和,但是实际中发现 multiprocessing中的Queue似乎对numpy的数据的处理有些bug。
以下是一份demo代码,开始的想法是在多个子进程中直接将计算的矩阵put进Queue中,父进程阻塞,等子进程计算完后,再在父进程中将矩阵一个个get出来再相加,下面这份代码应该是能正常跑的。
import numpy as np
import multiprocessing
from multiprocessing import Queue
import time
def checkWrong(resultQueue, t):
while t:
mat = np.ones((10,1))
time.sleep(0.5)
resultQueue.put(mat)
t -= 1
if __name__ == '__main__':
resultQ = Queue()
t = 10
proc1 = multiprocessing.Process(target=checkWrong, args = (resultQ, t // 2) )
proc2 = multiprocessing.Process(target=checkWrong, args = (resultQ, t // 2) )
proc1.start()
proc2.start()
proc1.join()
proc2.join()
result = 0
while t:
result += resultQ.get()
t -= 1
print(result)
但是问题很快就来了,如果说put的矩阵太大,比如100*1,那么主进程就会卡死,实际发现子进程是已经结束的,但是不知道为什么主进程就一直卡在join那里。
import numpy as np
import multiprocessing
from multiprocessing import Queue
import time
def checkWrong(resultQueue, t):
while t:
mat = np.ones((100,1))
time.sleep(0.5)
resultQueue.put(mat)
t -= 1
if __name__ == '__main__':
resultQ = Queue()
t = 10
proc1 = multiprocessing.Process(target=checkWrong, args = (resultQ, t // 2) )
proc2 = multiprocessing.Process(target=checkWrong, args = (resultQ, t // 2) )
proc1.start()
proc2.start()
proc1.join()
proc2.join()
result = 0
while t:
result += resultQ.get()
t -= 1
print(result)
最后的解决方法就是不用join来阻塞,去掉join就可以了,利用Queue的get阻塞来阻塞父进程。如果这样写的话,即便要put的矩阵很大,例如1000000*1,也不会出现问题。
import numpy as np
import multiprocessing
from multiprocessing import Queue
import time
def checkWrong(resultQueue, t):
while t:
mat = np.ones((1000000,1))
time.sleep(0.5)
resultQueue.put(mat)
t -= 1
if __name__ == '__main__':
resultQ = Queue()
t = 10
proc1 = multiprocessing.Process(target=checkWrong, args = (resultQ, t // 2) )
proc2 = multiprocessing.Process(target=checkWrong, args = (resultQ, t // 2) )
proc1.start()
proc2.start()
result = 0
while t:
result += resultQ.get()
t -= 1
print(result)
总结
其实最后还是不清楚问题发生的原因,解决方法的话也不是万能的,例如如果不知道子进程要put多少个矩阵,那么父进程的循环就无法得知何时终止,不过在我的问题中是知道子进程会产生多少个矩阵的,因此可以解决问题。