HengGeneral 发表于 2013-11-13 15:12

python multiprocessing关于PicklingError的问题

大家接触到python多进程的一个典型的例子如下,程序执行起来也没有任何问题。
import multiprocessing

def f(x):
    return x*x

def go():
    pool = multiprocessing.Pool(processes=4)            
    #result = pool.apply_async(self.f, )   
    #print result.get(timeout=1)         
    print pool.map(f, range(10))


if __name__== '__main__' :
    go()
可是,一旦加入了class,程序就显示错误。程序和结果如下:
程序:
import multiprocessing

class someClass(object):
    def __init__(self):
      pass

    def f(self, x):
      return x*x

    def go(self):
      pool = multiprocessing.Pool(processes=4)            
      #result = pool.apply_async(self.f, )   
      #print result.get(timeout=1)         
      print pool.map(self.f, range(10))

结果:
PicklingError: Can't pickle <type 'instancemethod'>: attribute lookup __builtin__.instancemethod failed
请问有什么解决方法?
谢谢

Hadron74 发表于 2013-11-13 16:13

回复 1# HengGeneral

你在类里定义f,含有两个哑员self和x,map时就会出错。改成如下形式就没有问题了。import multiprocessing

def func(x):
    return x*x

class someClass(object):
    def __init__(self,func):
      self.f = func

    def go(self):
      pool = multiprocessing.Pool(processes=4)
      #result = pool.apply_async(self.f, )
      #print result.get(timeout=1)
      print pool.map(self.f, range(10))

a=someClass(func)
a.go()结果:$python f.py

laike9m 发表于 2013-11-13 16:38

回复 2# Hadron74


    能再解释一下么。。map时出错是指?

Hadron74 发表于 2013-11-13 16:47

回复 3# laike9m

我不是太理解map的过程,但是它必须把self对象传递到各个进程中才行,由于map只需要一个参数,self多了出来。我看了《Python标准库》,这里介绍的是它上的做法。
至于为什么报pickle的错,我也不明白。
   

laike9m 发表于 2013-11-13 23:03

回复 4# Hadron74


    我在SO上看到了这个问题,想必LZ应该也看到了:
http://stackoverflow.com/questions/1816958/cant-pickle-type-instancemethod-when-using-pythons-multiprocessing-pool-ma
http://stackoverflow.com/questions/7016567/picklingerror-when-using-multiprocessing

我在Python3.3.2 下测试,结果发现并没有这个问题。见下图:


然后在2.7下测试,同样报错,信息和LZ相同。

所以基本可以推断Python 3通过某种途径把这个bug解决了,让bound method也pickleable

然后找到了这个http://bugs.python.org/issue9276

在最后一行看见


说明确实Python 3修复了这个问题。根据上面提到的,参考pep-3154,有这样一段内容:


大意就是说,因为PEP-3155实现了__qualname__ (qualified name)这个属性,所以Python的pickle已经能够序列化以前不能的东西,比如bound和unbound method。

唯一有点奇怪的是,PEP 3154对应的版本是Python3.4,但是在3.3.2里面已经有了,不知道为什么
class A():
      def f(self,n):
            print(n)

a = A()
import pickle
pickle.dump((A,a), open('a.p', 'wb'))
大家可以试试执行上面那段简单的代码,应该可以(至少我可以)正确生成a.p文件

Hadron74 发表于 2013-11-14 11:48

回复 5# laike9m
分析得很详细呀,谢谢!

   

laike9m 发表于 2014-03-26 20:05

看了下python3.4的更新日志,确实有PEP3154,总之往后应该确定的没问题了
页: [1]
查看完整版本: python multiprocessing关于PicklingError的问题