【问题标题】:Passing sympy lambda to multiprocessing.Pool.map将 sympy lambda 传递给 multiprocessing.Pool.map
【发布时间】:2017-07-13 15:26:29
【问题描述】:

我想并行执行一个 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' 的效果完全相同。

【问题讨论】:

  • 你不能使用multiprocessing.Pool.map()跨进程调用live对象实例的方法,除非你特意解释目标子进程如何重建你的live 对象在其一侧。例如,检查this answer
  • @zwer 当然可以,但是没有解释第2点和第3点。

标签: python multiprocessing sympy


【解决方案1】:

对象Mult 在创建时没有字段。因此,它可以与股票 pickle 库一起腌制。然后,当您调用lambdify 时,您将_lambdify 属性添加到包含lambda 表达式的对象,该表达式不能被腌制。这会导致map 函数失败

这解释了为什么在调用lambdify 之前可以腌制对象并使用Pool.map,以及为什么在调用之后它会失败。 当你在lambdify中取消注释时,你并没有将属性添加到类中,调用lambdifyMult对象仍然可以被pickle。

【讨论】:

  • 这听起来像是解释了一切。您是否有“您将 _lambdify 属性添加到包含无法腌制的 lambda 表达式的对象”的参考?
  • This reference 解释为什么不能腌制 lambda 表达式。请注意,dill 显然可以序列化来自sympy.lambdify 的结果。
  • 我的错,dill 也无法腌制 sympy 对象。
  • 哦,对不起,我不明白你第一次说什么。你是完全正确的。改变的是我尝试腌制一个包含 lambda 的对象。
【解决方案2】:

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

【讨论】:

  • 谢谢!确实,loky 很了不起。 joblib的界面也挺好用的。
猜你喜欢
  • 2021-12-27
  • 1970-01-01
  • 2020-12-31
  • 1970-01-01
  • 2022-01-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多