2014-12-05 84 views
0

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

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

'os.execv'替换子进程后。你不想这样做。尝试'subprocess.call(['/ bin/sleep',str(t)])''。 – tdelaney 2014-12-05 01:50:50

+0

但是第一次通话后它会死掉,不是吗? – Groot 2014-12-05 02:21:00

+0

我不确定,可能有一些恢复协议。 – tdelaney 2014-12-05 03:33:00

回答

0

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

解决方案是使用函数(如subprocess.call)来完成要运行的代码的完整分支和执行。这样可以让孩子的过程保持完整,并且能够将结果传递给父母。

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

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() 
+0

我是Python的新手,但是我认为“多处理”会做fork/join(和“pool.join()”)似乎会加强这种印象。如果它没有执行fork/join,那么execv()会导致问题是有道理的。但是这4个子进程让我陷入了一个循环;因为它似乎工作,我不认为execv()是一个问题 – Groot 2014-12-05 17:57:58

+0

在Linux中,多处理做了一个分叉来创建其子。问题是你做了一个没有额外分支的exec,所以孩子的multiprocessing.Pool协议丢失了。在我看来,多处理父母应该抛开一个例外,因为从孩子的角度来看,这个孩子已经完全崩溃了。否则,我们只能猜测。 – tdelaney 2014-12-05 18:13:53