如果你打开一个Jupyter笔记本并运行它:
import multiprocessing
def f(x):
a = 3 * x
pool = multiprocessing.Pool(processes=1)
global g
def g(j):
return a * j
return pool.map(g, range(5))
f(1)
您将收到以下错误
Process ForkPoolWorker-1:
Traceback (most recent call last):
File "/Users/me/anaconda3/lib/python3.5/multiprocessing/process.py", line 249, in _bootstrap
self.run()
File "/Users/me/anaconda3/lib/python3.5/multiprocessing/process.py", line 93, in run
self._target(*self._args, **self._kwargs)
File "/Users/me/anaconda3/lib/python3.5/multiprocessing/pool.py", line 108, in worker
task = get()
File "/Users/me/anaconda3/lib/python3.5/multiprocessing/queues.py", line 345, in get
return ForkingPickler.loads(res)
AttributeError: Can't get attribute 'g' on <module '__main__'>
我试图了解这是一个错误还是一个功能。
我试图让它工作,因为在我的实际情况中f
基本上是一个易于并行化的for循环(每次迭代只更改一个参数),但每次迭代需要花费大量时间!我是否正确处理问题或者是否有更简单的方法? (注意:整个笔记本中f将被调用几次,不同的参数本身)
答案 0 :(得分:2)
如果您在g
之外定义f
,则可以正常工作。
import multiprocessing
def g(j):
return 4 * j
def f():
pool = multiprocessing.Pool(processes=1)
return pool.map(g, range(5))
f()
修改强>: 在示例中,您输入的问题可调用对象看起来有点像这样:
class Calculator():
def __init__(self, j):
self.j = j
def __call__(self, x):
return self.j*x
你的函数f
就像这样:
def f(j):
calculator = Calculator(j)
pool = multiprocessing.Pool(processes=1)
return pool.map(calculator, range(5))
我在这种情况下工作得很好。希望它有所帮助。
答案 1 :(得分:1)
如果要将g
应用于更多参数而不仅仅是pool.map
传递的迭代器元素,则可以使用functools.partial
,如下所示:
import multiprocessing
import functools
def g(a, j):
return a * j
def f(x):
a = 3 * x
pool = multiprocessing.Pool(processes=1)
g_with_a = functools.partial(g, a)
return pool.map(g_with_a, range(5))
f(1)
functools.partial
的作用是获取函数和任意数量的参数(通过位置和关键字)并返回一个新函数,其行为类似于传递给它的函数,但只接受参数没有传递给partial
。
partial
返回的函数可以顺利腌制i。即传递给pool.map
,只要你使用的是python3。
这与Darth Kotik在答案中描述的基本相同,但你不必自己实施Calculator
课程,因为partial
已经做了你想做的事。