最近在改bug的时候 , 需要让父进程给子进程传一个复杂对象 ,
直接
from multiprocessing import Process, Queue, Lock,Pipe,Manager
def func(arg):
pass
if __name__=='__main__':
Process(target=func,args=(arg,))
报错:不能被pickle ,不能序列化 . 于是考虑放到queue或者pipe中 , 又尝试用了dill (api和pickle一样) , 都报错:不能pickle.
谷歌到的内容 :
什么可以被 pickle
-
None,True,False,内建数字类型,字符串
-
picklable 对象组成的 tuple、list、set、dict
-
在模块顶层中定义的函数、内建函数、类
-
其
__dict__
或__getstate__()
是可 pickle 的类实例 -
特别地,numpy ndarray
注意 lambda
匿名函数不可被 pickle,除非使用 dill
之类的包,见此。
详见 http://luly.lamost.org/blog/python_multiprocessing.html
尝试了Manager ,付一个manager共享对象的例子:
from multiprocessing import Process,Value,Lock
from multiprocessing.managers import BaseManager
class Employee(object):
def __init__(self,name,salary):
self.name=name
self.salary=Value('i',salary)
def increase(self):
self.salary.value+=100
def getPay(self):
return self.name+':'+str(self.salary.value)
class MyManager(BaseManager):
pass
def Manager2():
m=MyManager()
m.start()
return m
MyManager.register('Employee',Employee)
def func1(em,lock):
with lock:
em.increase()
if __name__ == '__main__':
manager=Manager2()
em=manager.Employee('zhangsan',1000)
lock=Lock()
proces=[Process(target=func1,args=(em,lock))for i in xrange(10)]
for p in proces:
p.start()
for p in proces:
p.join()
print em.getPay()
但是依然报错 ,无法在多进程中共享我的复杂对象 , 找到的答案是因为manager的通信接口过于简单,仅仅多支持了一些connection,event等类型 .
目前用线程替换了进程 , 线程的好处是子线程传参不需要序列化 , 且在多线程中可以拿到同一个单例对象 ,多个线程共享内存,而多进程不行 ; python多线程适用于io密集型操作 ,而多进程适用于cpu密集型操作,用于科学计算比较多 , 目前的应用场景多线程可以满足要求 .
目前仍未找到更好的办法.