multiprocessing.pool 行为更改 -- 不起作用,抱怨freeze_support



下面是一个并行完成工作的简单脚本:

import multiprocessing as mp
def f(x):
return x+1
pool = mp.Pool(2)
res = pool.map(f, range(10))
pool.close()
print(res)

它曾经只是工作。 最近,它没有。 我不知道发生了什么变化,也许是 python 更新?

编辑:它在python 3.7.4中工作正常,但在3.8.3中不能

当我从ipython运行它时(特别是使用spyder),我得到以下内容,也是无限的:

Process SpawnPoolWorker-1:
Traceback (most recent call last):
File "/opt/anaconda3/envs/two_step_line/lib/python3.8/multiprocessing/process.py", line 315, in _bootstrap
self.run()
File "/opt/anaconda3/envs/two_step_line/lib/python3.8/multiprocessing/process.py", line 108, in run
self._target(*self._args, **self._kwargs)
File "/opt/anaconda3/envs/two_step_line/lib/python3.8/multiprocessing/pool.py", line 114, in worker
task = get()
File "/opt/anaconda3/envs/two_step_line/lib/python3.8/multiprocessing/queues.py", line 358, in get
return _ForkingPickler.loads(res)
AttributeError: Can't get attribute 'f' on <module '__main__' (built-in)>
Process SpawnPoolWorker-2:
Traceback (most recent call last):
File "/opt/anaconda3/envs/two_step_line/lib/python3.8/multiprocessing/process.py", line 315, in _bootstrap
self.run()
File "/opt/anaconda3/envs/two_step_line/lib/python3.8/multiprocessing/process.py", line 108, in run
self._target(*self._args, **self._kwargs)
File "/opt/anaconda3/envs/two_step_line/lib/python3.8/multiprocessing/pool.py", line 114, in worker
task = get()
File "/opt/anaconda3/envs/two_step_line/lib/python3.8/multiprocessing/queues.py", line 358, in get
return _ForkingPickler.loads(res)
AttributeError: Can't get attribute 'f' on <module '__main__' (built-in)>
Process SpawnPoolWorker-3:

这曾经只是工作。 我在 mac 上使用 python 3.8.3,该脚本适用于 python 3.7.4。

更重要的是,我该如何解决这个问题?

编辑2:我想我可以把它包起来

if __name__ == "__main__":
pool...

如果我将脚本保存到.py文件,它将从命令行找到。 但它不能相互作用。 我通常以交互方式进行开发,这种更改很烦人。 有谁知道如何在python 3.8.3中交互运行简单的mp循环?

Edit3:显然,问题源于这样一个事实,即 3.8 中的多处理现在在 mac 上默认spawn而不是fork。 出于某种原因,分叉是"不安全的"。 我不关注讨论,但一个简单的、可能"不安全"的解决方法是

mp.set_start_method('fork')

过去几天我一直在 Spyder 中使用 Pool 进行多处理,遇到了与您类似的问题。我无法以交互方式运行任何多处理代码(作为代码块),但我能够通过以下方式运行多处理代码:

from multiprocessing import Pool
def main():
with Pool(5) as p:
...do multiprocessing here
if __name__ == "__main__":
main()

当我通过按绿色播放按钮(或 F5)运行文件时,多处理代码正确执行。

经过大量的挖掘和几个死胡同,我把一些有用的东西放在一起!只需对代码进行少量重组,我们就可以在Spyder4中获得交互式多处理。

首先,我们需要确保我们使用的是IPython控制台。我们可以通过重新启动Spyder中的控制台并验证"IPython 7.xx.x"是否已打印来确认这一点。

其次,我们需要将我们想要交互的多处理代码移动到另一个文件中,并将其包装在main()中。下面是一个可能看起来像什么的示例(暂时忽略有关varFromInteractive的警告 - 这将来自交互式代码单元的部分):

from multiprocessing import Pool
def f(a):
return a**2
def multiprocessTest():
with Pool(5) as p:
out = p.map(f, range(varFromInteractive))
return out
def main():
print('executing test.py')
testing = multiprocessTest()
print('multiprocessing results: ', testing)

varFromTest = 'it worked!'
if __name__ == "__main__":
main()

假设我们将上述多处理代码保存在文件 test.py 中。

接下来,在我们的交互式文件中,我们有我们希望运行的各个单元格(单元格是通过键入创建的# %%),我们可以输入:

# %%    
from IPython import get_ipython
# %%
varFromInteractive = 10
get_ipython().run_line_magic('run', '-i test.py')
# %%
print(varFromTest)

运行这三个单元时,我收到了输出:

runcell(19, 'C:/Users/redacted/exploration.py')
runcell(27, 'C:/Users/redacted/exploration.py')
executing test.py
multiprocessing results:  [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
runcell(28, 'C:/Users/redacted/exploration.py')
it worked!

这太棒了,因为不仅多处理代码正在执行,而且 test.py 中的多处理代码可以访问变量varFromInteractive,而单独文件中的交互式代码可以访问变量varFromTest

那么,这项工作的魔力是什么?好吧,顺便说一句,IPython魔法。

get_ipython().run_line_magic('run','-i test.py')行告诉 IPython shell 执行文件test.py中包含的代码,-i参数的意思是"在 IPython 的命名空间中运行文件而不是空文件"[source]。此外,"该文件在最初仅由 __name__='__main__' 和 sys.argv 组成的命名空间中执行,如所示构造"[同一来源]。

据我了解,Spyder曾经在代码单元中原生支持IPython魔术,因此可以编写%run -i test.py。情况已不再如此,如以下 github 问题中所述:

IPython magics不是有效的Python代码,所以我们决定不再在Python文件中支持它们。这将避免在Spyder中工作但不能在Spyder之外工作的文件的常见问题。

该信息的海报ccordoba12也给出了如何在Spyder4中使用IPython魔法的例子:

from IPython import get_ipython
get_ipython().magic('who print')

该信息与上面链接的IPython文档和这些IPython文档相结合,以产生解决方案。

问题的海报使用Mac,我使用Windows PC,但我希望解决方案可以翻译。

最新更新