concurrent.futures代码中的死锁

时间:2012-02-09 15:57:31

标签: python multiprocessing concurrent.futures

我一直在尝试使用concurrent.futures.ProcessPoolExecutor并行化一些代码,但一直存在ThreadPoolExecutor未出现的奇怪死锁。一个最小的例子:

from concurrent import futures

def test():
    pass

with futures.ProcessPoolExecutor(4) as executor:
    for i in range(100):
        print('submitting {}'.format(i))
        executor.submit(test)

在python 3.2.2(在64位Ubuntu上),这似乎在提交所有作业后一直挂起 - 这似乎发生在提交的作业数量大于工作人员数量的情况下。如果我将ProcessPoolExecutor替换为ThreadPoolExecutor,则可以完美无缺地工作。

作为调查的尝试,我给了每个未来一个回调来打印i的值:

from concurrent import futures

def test():
    pass

with futures.ProcessPoolExecutor(4) as executor:
    for i in range(100):
        print('submitting {}'.format(i))
        future = executor.submit(test)

        def callback(f):
            print('callback {}'.format(i))
        future.add_done_callback(callback)

这让我更加困惑 - i打印出来的callback的值是调用它时的值,而不是它定义时的值(所以我从未看到{ {1}}但我得到了很多callback 0 s。同样,callback 99打印出预期值。

想知道这可能是一个bug,我尝试了python的最新开发版本。现在,代码至少似乎终止了,但我仍然打印出错误的ThreadPoolExecutor值。

所以任何人都可以解释:

  • 在python 3.2和显然解决这个死锁的当前开发版本之间i发生了什么

  • 为什么要打印ProcessPoolExecutor的'错误'值

编辑:正如jukiewicz在下面指出的,当然打印i将在调用回调时打印值,我不知道我在想什么...如果我传递一个可调用的对象i的值作为其属性之一,按预期工作。

编辑:更多信息:所有回调都被执行,因此看起来i(由executor.shutdown调用)无法判断进程是否已完成。这似乎在当前的python 3.3中完全修复了,但似乎对executor.__exit__multiprocessing进行了很多更改,所以我不知道是什么修复了这个。由于我不能使用3.3(它似乎与numpy的发行版或开发版本兼容),我尝试简单地将其多处理和并发包复制到我的3.2安装,这似乎工作正常。不过,看起来有点奇怪 - 据我所知 - concurrent.futures在最新版本中完全被破坏了,但没有其他人受到影响。

1 个答案:

答案 0 :(得分:2)

我修改了如下代码,解决了这两个问题。 callback函数被定义为闭包,因此每次都会使用i的更新值。至于死锁,这可能是在所有任务完成之前关闭Executor的原因。等待期货完成也解决了这个问题。

from concurrent import futures

def test(i):
    return i

def callback(f):
    print('callback {}'.format(f.result()))


with futures.ProcessPoolExecutor(4) as executor:
    fs = []
    for i in range(100):
        print('submitting {}'.format(i))
        future = executor.submit(test, i)
        future.add_done_callback(callback)
        fs.append(future)

    for _ in futures.as_completed(fs): pass

更新:哦,对不起,我还没看过您的更新,这似乎已经解决了。