设置maxtasksperchild时,使用Python multiprocessing.Pool失败

时间:2014-09-11 19:56:18

标签: python multiprocessing heisenbug

我在Linux上使用Python 2.7.8,并且在使用multiprocessing.Pool()的程序中看到一致的失败。当我将maxtasksperchild设置为None时,一切都很好,当测试各种过程值时。但是如果我设置maxtasksperchild = n(n> = 1),那么我总是以未捕获的异常结束。这是主要块:

if __name__ == "__main__":
    options = parse_cmdline()
    subproc = Sub_process(options)

    lock = multiprocessing.Lock()
    [...]
    pool = multiprocessing.Pool(processes=options.processes,
                                maxtasksperchild=options.maxtasksperchild)
    imap_it = pool.imap(recluster_block, subproc.input_block_generator())
    #import pdb; pdb.set_trace()
    for count, result in enumerate(imap_it):
        print "Count = {}".format(count)
        if result is None or len(result) == 0:
            # presumably error was reported
            continue
        (interval, block_id, num_hpcs, num_final, retlist) = result
        for c in retlist:
            subproc.output_cluster(c, lock)
    print "About to close_outfile."
    subproc.close_outfile()
    print "About to close pool."
    pool.close()
    print "About to join pool."
    pool.join()

为了进行调试,我添加了一个print语句,显示循环的次数。这是几个运行:

$ $prog  --processes=2 --maxtasksperchild=2
Count = 0
Count = 1
Count = 2
Traceback (most recent call last):
  File "[...]reclustering.py", line 821, in <module>
    for count, result in enumerate(imap_it):
  File "[...]/lib/python2.7/multiprocessing/pool.py", line 659, in next
    raise value
TypeError: 'int' object is not callable

$ $prog --processes=2 --maxtasksperchild=1
Count = 0
Count = 1
Traceback (most recent call last):
[same message as above]

如果我没有设置maxtasksperchild,程序将成功运行完成。此外,如果我取消注释“import pdb; pdb.set_trace()”行并输入调试器,则不会出现问题(Heisenbug)。那么,我在这里的代码中做错了吗?是否有生成输入的代码(subproc.input_block_generator)或处理它的代码(recluster_block)的条件,已知会导致这样的问题?谢谢!

1 个答案:

答案 0 :(得分:1)

maxtasksperchild导致多处理重新生成子进程。我们的想法是摆脱任何正在建立的残余。问题是,你可以从父母那里得到新的东西。当孩子重生时,它获得父进程的当前状态,这与orignal spawn不同。您正在脚本的全局命名空间中进行工作,因此您正在改变孩子将会看到的环境。具体来说,您使用一个名为&#39; count&#39;的变量。这掩盖了以前从itertools导入计数&#39;言。

解决此问题:

  1. 使用命名空间(itertools.count,就像你在评论中所说的那样)来减少名称冲突

  2. 在函数中完成工作,以便局部变量不会传播给孩子。