我用 multiprocessing.Pool 来对类方法进行多进程。 然后以下报错: cPickle.PicklingError: Can't pickle <type 'instancemethod'>: attribute lookup builtin.instancemethod failed
之后查了一下,说 multiprocessing 默认只支持不在类里面的函数或者类里面的 @staticmethod,于是用
import copy_reg
import types
def _pickle_method(m):
if m.im_self is None:
return getattr, (m.im_class, m.im_func.func_name)
else:
return getattr, (m.im_self, m.im_func.func_name)
copy_reg.pickle(types.MethodType, _pickle_method)
这段代码,解决了上面的错误,但是又以下报错: TypeError: can't pickle thread.lock objects
然后又查了貌似是类中有些变量不能序列化导致的,然后想请教下这种情况怎么解决啊。 我看了些资料说是可以重写__getstate__和__setstate__魔法方法,但也不知道其参数是怎么传的。也有说将类设成全局变量,然后 pool.apply 的时候就不需要把类传进去,但是这样发现,类会初始化多次,请问要怎么解决呢?
1
wuwukai007 2019-11-20 09:21:21 +08:00
pip install dill
dill.dumps(obj) |
2
xiaolinjia OP @wuwukai007 这个 obj 指的是?
|
3
wuwukai007 2019-11-20 09:34:03 +08:00
你要序列化的对象啊,可以是函数,类,内嵌函数,用的时候在 dill.loads(obj)
|
4
wuwukai007 2019-11-20 09:34:53 +08:00
a = dill.dumps(obj)
把 a 当作参数放到 进程的 args 里面 |
5
xiaolinjia OP @wuwukai007 我进程的 args 里面的参数是可以 pickle 的,可能是进程里的类方法里有些类成员不能 pickle。
|
6
wuwukai007 2019-11-20 09:46:54 +08:00
你开多进程,把这个类序列化,传进去当参数,类里面的方法会报错?
|
7
xiaolinjia OP @wuwukai007 我补充了一下问题,我调用的时候是在 main 方法中:
client = Client() from multiprocessing import Pool pool = Pool(processes=2) for url in ['ws://192.168.0.18:9988/websocket/37', 'ws://192.168.0.18:9988/websocket/44']: pool.apply_async(func=client.received_message, args=(url,)) pool.close() pool.join() |
8
xiaolinjia OP @xiaolinjia 那个空格被吃了,
client = Client() from multiprocessing import Pool pool = Pool(processes=2) for url in ['ws://192.168.0.18:9988/websocket/37', 'ws://192.168.0.18:9988/websocket/44']: ----pool.apply_async(func=client.received_message, args=(url,)) pool.close() pool.join() |
9
hustlibraco 2019-11-20 10:00:21 +08:00
一般不建议这么搞,进程之间共享的数据最好只是整型、字符串,每个进程单独创建一个 client 比较好。强行修改序列化对象一个是不安全,一个是复杂不可重用。
|
10
xiaolinjia OP @hustlibraco 其实我也有想过这个,不过就是单独创建一个实例的话,会多次初始化,但是我又想只初始化一次。
|
11
aaronhua 2019-11-20 10:18:25 +08:00
看着自己堆的一坨坨 shi 山,不禁感慨,有时候代码简单点,效率低点也没有关系。
|
12
wuwukai007 2019-11-20 10:33:44 +08:00
socket 对象好像不能被序列化把
|
13
xiaolinjia OP @wuwukai007 socket 这里,我刚才单独测试的时候应该是没问题,因为他是每个进程内,才创建的。应该不会参与序列化这块。。
|
14
wuwukai007 2019-11-20 11:33:31 +08:00
copy_reg.pickle(types.MethodType, _pickle_method)
你这一步报错 把这一步换成 dill.dumps(_pickle_method) 试一下, |
15
xiaolinjia OP @wuwukai007 这个连第一步都失败了,现在总结得出,应该是有个数据库的持续化链接的问题,就是 self.db 。其他的 websocket,rabbitmq,因为都是在进程内创建的都没问题,应该就是剩下这个 oracle 的数据库链接不能 pickle 了
|
16
wuwukai007 2019-11-21 15:01:29 +08:00
oracle 数据库连接不能序列化, 用连接池 pip install DBUtils
|
17
hustlibraco 2019-11-22 14:00:55 +08:00
@xiaolinjia 不知道你有没有测试过,序列化对象的性能开销和对象重新创建的性能开销,谁更大
|