multiprocessing.Pool在Windows正常但在Ubuntu不行?
解决了:问题出在Wingware Python IDE上。我想现在自然会有人问,这怎么可能,以及如何解决这个问题。
我昨天问了一个问题( Python中的multiprocessing.Pool问题),这个问题几乎是一样的,但我发现它在Windows电脑上能正常工作,而在我的Ubuntu上却不行。在这篇文章的最后,我会发布一个稍微不同的代码版本,它能做同样的事情。
我的问题简要总结:在Python中使用multiprocessing.Pool时,我并不总是能得到我请求的工作进程数量。当这种情况发生时,程序就会卡住。
我整整一天都在寻找解决方案,然后我想到了诺亚在我之前问题下的评论。他说他的机器上能正常工作,所以我把代码给了我的同事,他用的是Windows机器,运行的是Enthought的64位Python 2.7.1版本。我也用的是同样的版本,但我的机器是在Ubuntu上运行的。我还提到我们俩都在用Wingware Python IDE,但我怀疑这是否重要?
我的代码中有两个问题,而这些问题在我同事的机器上并不存在。
我并不总是能得到我请求的四个工作进程(尽管我的机器有12个工作进程)。当这种情况发生时,进程就会卡住,不会继续。没有抛出任何异常或错误。
当我能得到我请求的四个工作进程时(大约每五次中有一次),生成的数字(纯随机数)在四个图像中是完全相同的。而我同事的情况则不是这样。
这情况很奇怪,我非常感谢你们能提供的任何帮助。
代码:
import multiprocessing as mp
import scipy as sp
import scipy.stats as spstat
import pylab
def testfunc(x0, N):
print 'working with x0 = %s' % x0
x = [x0]
for i in xrange(1,N):
x.append(spstat.norm.rvs(size = 1)) # stupid appending to make it slower
if i % 10000 == 0:
print 'x0 = %s, i = %s' % (x0, i)
return sp.array(x)
def testfuncParallel(fargs):
return testfunc(*fargs)
# Define Number of tasks.
nTasks = 4
N = 100000
if __name__ == '__main__':
"""
Try number 1. Using multiprocessing.Pool together with Pool.map_async
"""
pool = mp.Pool(processes = nTasks) # I have 12 threads (six cores) available so I am suprised that it does not get access to nTasks = 4 amount of workers
# Define tasks:
tasks = [(x, n) for x, n in enumerate(nTasks*[N])] # nTasks different tasks
# Compute parallel: async - asynchronically, i.e. not necessary in order.
result = pool.map_async(testfuncParallel, tasks)
pool.close() # These are needed if map_async is used
pool.join()
# Get results:
sim = sp.zeros((N, nTasks))
for nn, res in enumerate(result.get()):
sim[:, nn] = res
pylab.figure()
for i in xrange(nTasks):
pylab.subplot(nTasks,1, i + 1)
pylab.plot(sim[:, i])
pylab.show()
提前谢谢你们。
真诚的,
Matias
2 个回答
我没有你第一个问题的解决办法。实际上,我在我的64位Ubuntu系统上,使用Enthought的Python 2.7.1 [EPD 7.0-2 (64-bit)],可以毫无问题地多次运行你的代码。补充说明:问题其实是由你的IDE(Wingware)引起的。一个简单的解决办法就是在IDE外面运行这个脚本。
至于第二个问题,发生的情况是,在Unix系统上,每个工作进程都会从父进程那里继承相同的随机数生成器状态。这就是为什么它们会生成相同的伪随机序列。要解决这个问题,你只需要在testfunc
的开头调用一下scipy.random.seed
:
def testfunc(x0, N):
sp.random.seed()
print 'working with x0 = %s' % x0
...
更新:结果发现这和matplotlib或其后端没有关系,而是和多进程的一些问题有关。我们已经在Wing版本4.0.4及以上修复了这个问题。解决方法是不要在子进程中执行的代码里设置断点。
看起来是Wing IDE对Tkinter后端的matplotlib支持和多进程之间有冲突。当我尝试这个例子时,它在TCL/Tk代码中崩溃。我怀疑在Windows上工作的人使用了不同的matplotlib后端。
在项目属性的扩展选项卡中关闭“matplotlib事件循环支持”似乎可以解决这个问题。
或者,当“matplotlib事件循环支持”开启时,添加以下代码似乎可以解决我的问题。
import matplotlib
matplotlib.use('WXAgg')
这只有在你有WXAgg后端的情况下才有效。Wing IDE支持的其他后端(这样即使调试过程暂停,图表仍然可以交互)有GTKAgg和Qt4Agg,但我还没有尝试过这些。
我会看看能否找到并修复这个问题。我怀疑我们需要在进程ID改变时禁用我们的事件循环支持。谢谢你报告这个问题。