Python 并发代码中的死锁
我一直在尝试使用Python 并发代码中的死锁,python,multiprocessing,concurrent.futures,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('submitti
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)
在Python3.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)
这让我更加困惑,callback
打印出来的i
的值是调用它时的值,而不是定义它时的值(因此我从未看到callback0
,但我得到了很多callback99
s)。同样,ThreadPoolExecutor
打印出预期值
想知道这是否是一个bug,我尝试了python的最新开发版本。现在,代码似乎至少终止了,但我仍然打印出了错误的I
值
那么,谁能解释一下:
- 在Python3.2和显然修复了此死锁的当前开发版本之间,
发生了什么ProcessPoolExecutor
- 为什么打印
的“错误”值i
i
会在调用回调时打印值,我不知道我在想什么。。。如果我将值为I
的可调用对象作为其属性之一传递给它,那么它将按预期工作
编辑:更多一点信息:所有回调都已执行,因此看起来好像是
executor.shutdown
(由executor.\uuuu exit\uuuu
调用)无法判断进程是否已完成。在当前的Python3.3中,这似乎是完全固定的,但是,多处理
和并发.futures
似乎有很多变化,所以我不知道是什么解决了这一问题。由于我不能使用3.3(它似乎与numpy的发行版或开发版本都不兼容),我尝试将其多处理和并发软件包复制到我的3.2安装中,这似乎很好。尽管如此,就我所见,ProcessPoolExecutor
在最新版本中被完全破坏,但没有其他人受到影响,这似乎有点奇怪。我对代码进行了如下修改,解决了这两个问题callback
函数被定义为闭包,因此每次都会使用更新后的i
值。至于死锁,这可能是在所有任务完成之前关闭执行器的原因。等待未来完成也解决了这一问题
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
更新:哦,对不起,我还没有读你的更新,这似乎已经解决了。至于第二个问题,处理print
99是很自然的。symboli
受全局上下文的约束,创建新进程的成本很高,所以当你开始执行任何事情时,i==99
。另外,我有Ubuntu 64位,Python 3.2.2,第一个代码段没有挂起…@julkiewicz:这很奇怪。我刚刚在另一台运行64位Scientific Linux和python 3.2.2的机器上试用了它,在10次试用中打印了10次“提交99”后,它就停止了。我甚至尝试过在中包装代码,如果我听说在Windows上进行多处理是必要的,那么就用来包装代码。事实上,我看不到发生这种情况所需的作业和工人数量的模式。例如,1个工人和2个工作是可以的,1个工人和3个工作挂起,8个工人和16个工作挂起大约一半的时间。