如何在不处于顶层的情况下解决python多处理的酸洗错误?

时间:2015-03-03 00:24:57

标签: python multiprocessing pickle python-multiprocessing

我已经多次研究过这个问题,但是没有找到一个可以在我的情况下工作的解决方法,或者我理解的解决方法,所以请耐心等待。

基本上,我有一个功能的层次组织,这使我无法在顶层进行多处理。不幸的是,我不相信我可以改变程序的布局 - 因为我需要在初始输入后创建的所有变量。

例如,说我有这个:

import multiprocessing

  def calculate(x):
    # here is where I would take this input x (and maybe a couple more inputs)
    # and build a larger library of variables that I use further down the line

    def domath(y):
      return x * y

    pool = multiprocessing.Pool(3)
    final= pool.map(domath, range(3))

calculate(2)

这会产生以下错误:

Can't pickle <type 'function'>: attribute lookup __builtin__.function failed

我在考虑全局,但我担心我必须定义太多,这可能会使我的程序减慢很多。 是否有任何解决方法而无需重组整个计划?

3 个答案:

答案 0 :(得分:7)

您可以使用pathos.multiprocessing,它是multiprocessing的分支,使用dill序列化程序代替pickledill可以在python中序列化几乎任何东西。然后,无需编辑代码。

>>> from pathos.multiprocessing import ProcessingPool as Pool
>>> 
>>> def calculate(x):
...   def domath(y):
...     return x*y
...   return Pool().map(domath, range(3))
... 
>>> calculate(2)
[0, 2, 4]

你甚至可以坚持下去......因为大多数东西都被腌制了。不需要使用纯multiprocessing烹饪的奇怪的非pythonic解决方案。

>>> class Foo(object):
...   def __init__(self, x):
...     self.x = x
...   def doit(self, y):
...     return ProcessingPool().map(self.squared, calculate(y+self.x))
...   def squared(self, z):
...     return z*z
... 
>>> def thing(obj, y):
...   return getattr(obj, 'doit')(y)
... 
>>> ProcessingPool().map(thing, ProcessingPool().map(Foo, range(3)), range(3))
[[0, 0, 0], [0, 4, 16], [0, 16, 64]]

在此处获取pathoshttps://github.com/uqfoundation

答案 1 :(得分:3)

您遇到的问题实际上是一个功能。 pickle源实际上是为防止这种行为而设计的,以防止恶意代码被执行。在解决任何适用的安全实施时,请考虑这一点。

首先我们有一些进口。

import marshal
import pickle
import types

这里我们有一个函数,它接受一个函数作为参数,pickle对象的部分,然后返回一个包含所有部分的元组:

def pack(fn):
    code = marshal.dumps(fn.__code__)
    name = pickle.dumps(fn.__name__)
    defs = pickle.dumps(fn.__defaults__)
    clos = pickle.dumps(fn.__closure__)
    return (code, name, defs, clos)

接下来我们有一个函数,它接受转换函数的四个部分。它翻译这四个部分,然后创建然后从这些部分返回一个函数。你应该注意全局变量被重新引入这里,因为我们的过程不处理这些:

def unpack(code, name, defs, clos):
    code = marshal.loads(code)
    glob = globals()
    name = pickle.loads(name)
    defs = pickle.loads(defs)
    clos = pickle.loads(clos)
    return types.FunctionType(code, glob, name, defs, clos)

这里我们有一个测试功能。注意我在函数范围内放了一个导入。全球不通过我们的酸洗过程来处理:

def test_function(a, b):
    from random import randint
    return randint(a, b)

最后,我们打包测试对象并打印结果以确保一切正常:

packed = pack(test_function)
print((packed))

最后,我们解压缩我们的函数,将它分配给变量,调用它并打印它的输出:

unpacked = unpack(*packed)
print((unpacked(2, 20)))

如果您有任何问题,请发表评论。

答案 2 :(得分:0)

如何将嵌入式功能取出来?

在我看来,这是最清晰的解决方案(因为你没有给出预期的输出,我不得不猜测):

$ cat /tmp/tmp.py
import multiprocessing

def calculate(x):
    # here is where I would take this input x (and maybe a couple more inputs)
    # and build a larger library of variables that I use further down the line

    pool = multiprocessing.Pool(3)
    _lst = [(x, y) for x in (x,) for y in range(3)]
    final= pool.map(domath, _lst)
    print(final)

def domath(l):
    return l[0] * l[1]

calculate(2)

$ python /tmp/tmp.py
[0, 2, 4]

$