我是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"有什么神奇的,我做错了什么?
答案 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()