Pool.map在4次迭代后挂起

时间:2014-12-05 01:39:46

标签: python multiprocessing

我是Python和多处理的新手。我想批量转换一堆文件,所以我想我尝试多处理。 Pool和map()概念似乎很简单,但它似乎不起作用。我把它减少到下面的测试程序,但它的要点是:它将经历4次迭代(在Pool中的每个进程)并在此之后挂起。这是测试代码:

import multiprocessing, logging
import os
import sys

mpl = multiprocessing.log_to_stderr()
mpl.setLevel(logging.INFO)

def chill(t):
    cmd  = '/bin/sleep'
    args = (cmd,str(t))
    print >>sys.stderr, os.getpid(), args
    os.execv(cmd, args)

if __name__ == "__main__" :
    times = [ 1 ] * 100
    pool = multiprocessing.Pool(1)  # change this for more processes
    pool.map(chill, times)
    pool.close()
    pool.join()

当我运行它时,它会在第4次迭代后挂起。增加进程数只会使进程数量增加4倍。这个" 4"有什么神奇的,我做错了什么?

1 个答案:

答案 0 :(得分:0)

问题是os.execv取代了子进程,因此父进程和子进程之间的常规握手将丢失。 Pool.map()发送要在块中处理的参数。如果进程意外退出,mp将重新启动进程并发送另一个块。您可能已经在多处理模块中发现了一个错误,因为它继续在此异常情况下发送数据进行处理,然后等待永远不会到达的任务完成。

解决方案是使用诸如subprocess.call之类的函数来执行要运行的代码的完整fork和exec。这使子进程保持完整,并能够将结果传递回父进程。

通过对测试程序进行一些更改,可以更清楚地看到问题。

import multiprocessing, logging
import os
import sys
import subprocess as subp

mpl = multiprocessing.log_to_stderr()
mpl.setLevel(logging.INFO)

def chill(args):
    i, t = args
    cmd  = '/bin/sleep'
    args = (cmd,str(t))
    print >>sys.stderr, i, os.getpid(), args
    os.execv(cmd, args)
#    subp.call(['/bin/sleep', str(t)])

if __name__ == "__main__" :
    times = [(i,1) for i in range(100)]
    pool = multiprocessing.Pool(1)  # change this for more processes
    pool.map(chill, times)
    pool.close()
    pool.join()

地图已将工作分解为4个块然后在最后一个之后挂起

[INFO/PoolWorker-1] child process calling self.run()
0 9204 ('/bin/sleep', '1')
[INFO/PoolWorker-2] child process calling self.run()
25 9208 ('/bin/sleep', '1')
[INFO/PoolWorker-3] child process calling self.run()
50 9209 ('/bin/sleep', '1')
[INFO/PoolWorker-4] child process calling self.run()
75 9210 ('/bin/sleep', '1')
[INFO/PoolWorker-5] child process calling self.run()