将sympy lambda传递给multiprocessing.Pool.map

时间:2017-07-13 15:26:29

标签: python multiprocessing sympy

我想并行执行一个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'。

2 个答案:

答案 0 :(得分:2)

对象Mult在创建时没有字段。因此可以使用库存pickle库进行酸洗。然后,当您调用lambdify时,会向包含_lambdify表达式的对象添加lambda属性,该表达式无法进行腌制。这会导致map函数

失败

这解释了为什么在调用lambdify之前你可以挑选对象并使用Pool.map以及为什么它在通话后失败。 取消注释lambdify中的行时,不会将该属性添加到类中,并且在调用Mult后仍可以对lambdify对象进行pickle。

答案 1 :(得分:1)

尽管我还没有完全探索这一点,但我只是想记录一下,使用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]