pathos.ProcessingPool 和 pickle 之间的交互

Posted

技术标签:

【中文标题】pathos.ProcessingPool 和 pickle 之间的交互【英文标题】:Interaction between pathos.ProcessingPool and pickle 【发布时间】:2016-11-11 10:07:04 【问题描述】:

我有一个需要运行的计算列表。我正在使用

将它们并行化
from pathos.multiprocessing import ProcessingPool
pool = ProcessingPool(nodes=7)
values = pool.map(helperFunction, someArgs)

helperFunction 确实创建了一个名为Parameters 的类,该类在

相同的文件中定义
import otherModule
class Parameters(otherModule.Parameters):
    ...

到目前为止,一切都很好。 helperFunction 会做一些计算,基于Parameters 对象,改变它的一些属性,最后使用pickle 存储。以下是进行保存的辅助函数(来自不同模块)的相关摘录:

import pickle
import hashlib
import os
class cacheHelper():

    def __init__(self, fileName, attr=[], folder='../cache/'):
        self.folder = folder

        if len(attr) > 0:
            attr = self.attrToName(attr)
        else:
            attr = ''
        self.fileNameNaked = fileName
        self.fileName = fileName + attr

    def write(self, objects):
        with open(self.getFile(), 'wb') as output:
            for object in objects:
                pickle.dump(object, output, pickle.HIGHEST_PROTOCOL)

当它到达pickle.dump() 时,它会引发一个难以调试的异常,因为调试器不会进入实际面临该异常的工作人员。因此,我在转储发生之前创建了一个断点,并手动输入了该命令。这是输出:

>>> pickle.dump(objects[0], output, pickle.HIGHEST_PROTOCOL)
Traceback (most recent call last):
  File "/usr/local/anaconda2/envs/myenv2/lib/python2.7/site-packages/IPython/core/interactiveshell.py", line 2885, in run_code
    exec(code_obj, self.user_global_ns, self.user_ns)
  File "<ipython-input-1-4d2cbb7c63d1>", line 1, in <module>
    pickle.dump(objects[0], output, pickle.HIGHEST_PROTOCOL)
  File "/usr/local/anaconda2/envs/myenv2/lib/python2.7/pickle.py", line 1376, in dump
    Pickler(file, protocol).dump(obj)
  File "/usr/local/anaconda2/envs/myenv2/lib/python2.7/pickle.py", line 224, in dump
    self.save(obj)
  File "/usr/local/anaconda2/envs/myenv2/lib/python2.7/pickle.py", line 331, in save
    self.save_reduce(obj=obj, *rv)
  File "/usr/local/anaconda2/envs/myenv2/lib/python2.7/pickle.py", line 396, in save_reduce
    save(cls)
  File "/usr/local/anaconda2/envs/myenv2/lib/python2.7/pickle.py", line 286, in save
    f(self, obj) # Call unbound method with explicit self
  File "/usr/local/anaconda2/envs/myenv2/lib/python2.7/site-packages/dill/dill.py", line 1203, in save_type
    StockPickler.save_global(pickler, obj)
  File "/usr/local/anaconda2/envs/myenv2/lib/python2.7/pickle.py", line 754, in save_global
    (obj, module, name))
PicklingError: Can't pickle <class '__main__.Parameters'>: it's not found as __main__.Parameters

奇怪的是,当我不并行化时,这不会发生,即手动循环 helperFunction。我很确定我打开了正确的Parameters(而不是父类)。

我知道如果没有可重现的示例,很难进行调试,我不希望这方面有任何解决方案。也许更普遍的问题是:

通过另一个模块并行化使用pickle.dump()的代码时需要注意什么?

【问题讨论】:

【参考方案1】:

直接来自 Python docs。

12.1.4。什么可以腌制和不腌制?可以腌制以下类型:

无、真和假 整数、浮点数、复数 字符串、字节、字节数组 元组、列表、集合和 仅包含在模块顶层定义的可提取对象函数的字典(使用 def,而不是 lambda) 在模块顶层定义的内置函数 在模块顶层定义的类 此类类的实例,其__dict__ 或调用__getstate__() 的结果是可腌制的(有关详细信息,请参阅腌制类实例部分)。

其他的都不能腌制。在您的情况下,尽管鉴于您的代码摘录很难说,但我认为问题在于类 Parameters 没有在模块的顶层定义,因此它的实例不能被腌制。

使用pathos.multiprocessing(或其积极开发的分支multiprocess)而不是内置的multiprocessing的全部意义在于避免pickle,因为有太多东西后来无法转储. pathos.multiprocessingmultiprocess 使用 dill 而不是 pickle。如果你想调试一个worker,你可以使用trace。

注意 正如 Mike McKerns(multiprocess 的主要贡献者)正确地注意到的那样,有些情况即使 dill 也无法处理,尽管很难制定一些通用规则那件事。

【讨论】:

这个答案还可以,但有点不清楚。我同意,如果 OP 使用 dill 而不是 pickle 用于类内的 dump,那么对象酸洗的可能性更大,而且,是的,dill.detect.trace 可以阐明对象层次结构,即被腌制。在某些情况下,甚至dill 也无法处理,有时诸如跨未安装的多模块用户脚本定义的类实例之类的事情可能会导致dill 出错。我还建议 OP 通过修改dill.settings 尝试其他一些酸洗变体,或者尝试cloudpickle

以上是关于pathos.ProcessingPool 和 pickle 之间的交互的主要内容,如果未能解决你的问题,请参考以下文章

(*p)++和*(p++)和*p++的区别

P*P和&P三者的区别

sed中p和P有什么区别?

*a=p和*a=&p的区别是啥呀 *a=p是否相当于a=&p

++ * p和* p ++之间的差异

模p加法和模p乘法学习