pathos.ProcessingPool和pickle之间的交互

时间:2016-07-08 18:40:39

标签: python python-2.7 multiprocessing pickle pathos

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

并行化它们
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()时,它会引发一个难以调试的异常,因为调试器不会进入实际遇到该异常的worker。因此,我在转储发生之前创建了一个断点,并手动输入该命令。这是输出:

>>> 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 个答案:

答案 0 :(得分:3)

直接来自Python docs

  

<强> 12.1.4。什么可以腌制和去除?可以腌制以下类型:

     
      
  • 无,真,假
  •   
  • 整数,浮点数,复数
  •   
  • 字符串,字节,字节数组
  •   
  • 元组,列表,集和
  •   
  • 只包含在模块顶层定义的可选对象函数的字典(使用def,而不是lambda)
  •   
  • 在模块顶层定义的内置函数
  •   
  • 在模块顶层定义的类
  •   
  • 此类的实例__dict__或调用__getstate__()的结果是可选择的(有关详细信息,请参阅“修补类实例”一节)。
  •   

其他一切都无法腌制。在你的情况下,虽然在给出代码摘录的情况下很难说,我认为问题是类Parameters没有在模块的顶层定义,因此它的实例不能被腌制。

使用pathos.multiprocessing(或其积极开发的分叉multiprocess)代替内置multiprocessing的重点是避免pickle,因为也有很多事情后来都无法转储。 pathos.multiprocessingmultiprocess使用dill代替pickle。如果您想调试工作人员,可以使用trace

注意正如Mike McKerns(multiprocess的主要撰稿人)正确地注意到的那样,有些情况甚至dill都无法处理,尽管很难制定关于这个问题的一些普遍规则。