我想并行执行一个sympy lambda函数。 我不知道:
- 为什么它并行工作,尽管它是一个 lambda 函数
- 为什么当我尝试在没有池的情况下执行时它停止工作
- 如果我取消注释
lambdify
中的第一个返回,为什么它会起作用
显然,降价预处理器需要在代码上方有一行文本,所以这就是代码:
from multiprocessing import Pool
import sympy
from sympy.abc import x
def f(m):
return m.lambdify()(1)
class Mult():
def lambdify(self):
# return sympy.lambdify(x, 2*x, 'numpy')
self._lambdify = sympy.lambdify(x, 2 * x, 'numpy')
return self._lambdify
if __name__ == '__main__':
with Pool() as pool:
m = Mult()
print(pool.map(f, [m]))
print(pool.map(f, [m]))
print(f(m))
print(pool.map(f, [m]))
它打印:
[2]
[2]
2
PicklingError: Can't pickle <function <lambda> at 0x000000000DF0D048>: attribute lookup <lambda> on numpy failed
(我剪掉了回溯(
如果我取消评论,它可以正常工作:
[2]
[2]
2
[2]
我只在Windows上测试过,它与"numexpr"而不是"numpy"的工作方式完全相同。
对象Mult
在创建时没有字段。因此,它可以与库pickle
原料一起腌制。然后,当您调用lambdify
时,将_lambdify
属性添加到包含无法被酸洗的lambda
表达式的对象。这会导致map
功能失败
这就解释了为什么在调用lambdify
之前可以挑选对象并使用Pool.map
,以及为什么它在调用后失败。 当你取消注释lambdify
中的行时,你不会将属性添加到类中,并且Mult
对象在调用lambdify
后仍然可以被酸洗。
虽然我还没有完全探索这一点,但我只想记录在案的是,当使用 loky 而不是多处理时,同一个例子工作得很好:
from loky import get_reusable_executor
import sympy
from sympy.abc import x
def f(m):
return m.lambdify()(1)
class Mult():
def lambdify(self):
# return sympy.lambdify(x, 2*x, 'numpy')
self._lambdify = sympy.lambdify(x, 2 * x, 'numpy')
return self._lambdify
executor = get_reusable_executor()
m = Mult()
print('pool.map(f, [m])', list(executor.map(f, [m])))
print('pool.map(f, [m])', list(executor.map(f, [m])))
print('f(m)', f(m))
print('pool.map(f, [m])', list(executor.map(f, [m])))
带输出
pool.map(f, [m]) [2]
pool.map(f, [m]) [2]
f(m) 2
pool.map(f, [m]) [2]