不能使用setParseAction()方法来pickle Pyparsing表达式。需要多处理

时间:2015-01-11 03:05:33

标签: python pickle python-multithreading pyparsing python-multiprocessing

我最初的问题是我正在尝试执行以下操作:

def submit_decoder_process(decoder, input_line):
    decoder.process_line(input_line)
    return decoder

self.pool = Pool(processes=num_of_processes)
self.pool.apply_async(submit_decoder_process, [decoder, input_line]).get()

解码器在这里有点介绍,但重要的是解码器是一个用调用setParseAction()的PyParsing表达式初始化的对象。这使多处理使用的pickle失败,这反过来又失败了上述代码。

现在,这是我已经隔离和简化的pickle / PyParsing问题。 由于pickle失败,以下代码会产生错误消息。

import pickle
from pyparsing import *

def my_pa_func():
    pass

pickle.dumps(Word(nums).setParseAction(my_pa_func))

错误讯息:

pickle.PicklingError: Can't pickle <function wrapper at 0x00000000026534A8>: it's not found as pyparsing.wrapper

现在如果删除调用.setParseAction(my_pa_func),它将没有问题:

pickle.dumps(Word(nums))

我怎样才能解决这个问题?多处理使用泡菜,所以我猜不到它。据说使用dill的pathos包不够成熟,至少,我在Windows-64bit上安装它时遇到问题。我真的在这里摸不着头脑。

3 个答案:

答案 0 :(得分:5)

好的,这是受Rocksportrocker启发的解决方案:Python multiprocessing pickling error

我们的想法是在不同过程之间来回传递不能被腌制的物体,然后再过去&#34; undill&#34;它通过后:

from multiprocessing import Pool
import dill

def submit_decoder_process(decoder_dill, input_line):
    decoder = dill.loads(decoder_dill)  # undill after it was passed to a pool process
    decoder.process_line(input_line)
    return dill.dumps(decoder)  # dill before passing back to parent process

self.pool = Pool(processes=num_of_processes)

# Dill before sending to a pool process
decoder_processed = dill.loads(self.pool.apply_async(submit_decoder_process, [dill.dumps(decoder), input_line]).get())

答案 1 :(得分:0)

https://docs.python.org/2/library/pickle.html#what-can-be-pickled-and-unpickled

multiprocessing.Pool使用Pickle协议来序列化函数和模块名称(在您的示例中为setParseAction和pyparse),这些名称通过Pipe传递给子进程。

子进程一旦收到它们,就会导入模块并尝试调用该函数。问题是你传递的不是函数而是方法。要解决它,Pickle协议应该足够聪明,可以使用'user'参数构建'Word'对象,然后调用setParseAction方法。由于处理这些情况过于复杂,因此Pickle协议会阻止您序列化非顶级函数。

要解决您的问题,您可以指示Pickle的模块如何序列化setParseAction方法(https://docs.python.org/2/library/pickle.html#pickle-protocol),或者以传递给Pool.apply_async的方式可序列化的方式重构代码。

如果将Word对象传递给子进程并让它调用Word(),该怎么办?setParseAction()?

答案 2 :(得分:0)

我建议pathos.multiprocessing,如你所说。当然,我是pathos作者,所以我想这并不奇怪。您可能会遇到distutils错误,如下所示:https://github.com/uqfoundation/pathos/issues/49

使用dill的解决方案是一个很好的解决方法。您也可以放弃安装整个pathos软件包,只需安装pathos软件包的multiprocessing分叉(使用dill代替pickle )。您可以在此处找到它:http://dev.danse.us/packages或此处:https://github.com/uqfoundation/pathos/tree/master/external