3

我原来的问题是,我试图做到以下几点:无法使用setParseAction()方法腌制Pyparsing表达式。需要多处理

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() 

解码器是有点麻烦来形容这里,但重要的是,解码器是与PyParsing表达初始化的对象它调用setParseAction()。这会妨碍多处理使用的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)) 

我怎样才能得到解决呢?多重处理使用泡菜,所以我不能避免它,我猜。据说使用莳萝的pathos软件包还不够成熟,至少,我在安装Windows-64bit时遇到问题。我真的在这里挠头。

+0

~~ rant ~~:''pathos'已接近10岁......几乎整个时间都在积极发展(周期性地)。它通过'setuptools'安装。如果你使用'pre'标志,它可以用'pip'安装。我没有看到它不是一个“成熟”的软件包......除了最后一个稳定版本的版本号(除非版本号标准发生变化,否则*不是问题)。无论如何,感叹。由于版本编号,待发布的新版本将完全处理'pip'安装问题*。 –

回答

5

OK,这里是rocksportrocker启发了解决方案:Python multiprocessing pickling error

的想法是萝可它已经经过不同时通过来回进程之间的腌制,然后“undill”它的对象通过:

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()) 
+0

很高兴能够在'dill'模块的帮助下解决这个问题。我在过去对pyparsing进行了修改以支持酸洗,但我从来没有尝试过使用解析操作来解析解析器 - 这是一个很好的解决方案,我会看看是否有方法将它合并到pyparsing中。 – PaulMcG

0

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

的multiprocessing.Pool使用泡椒的协议序列化功能和模块名称(在你的榜样setParseAction和pyparse),它们通过管道输送到子进程。

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

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

如果将Word对象传递给子进程并让它调用Word()。setParseAction(),会怎样?

0

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

使用dill的解决方案是一个很好的解决方法。您也许可以放弃安装整个pathos包,并且只安装multiprocessing包(其使用dill而不是pickle)的pathos叉。你可以在这里找到它:http://dev.danse.us/packages或这里:https://github.com/uqfoundation/pathos/tree/master/external

+0

嗨迈克,那是我在github上打开这个问题的人。其实,首先我试图使用病态,但由于它由于各种原因没有为我安装,我不得不想出一些解决方法。无论如何,我希望在希望解决所有问题的时候使用病态。 – jazzblue

+0

是的,我发现这是你。我将上面的代码添加到了碰到相同的python bug的任何其他人,所以他们也可以链接到你的ticket。 无论如何,没有好的活动代码解决了所有问题。 :)但我正在积极努力,让灾难更容易安装。 –