[python学习笔记] - multiprocessing模块执行带装饰器的方法报错及解决方式

27 篇文章 0 订阅
16 篇文章 0 订阅

keyword:multiprocessing decorator pickle

参考

https://segmentfault.com/q/1010000008907475?utm_source=tag-newest
http://ralph-wang.github.io/blog/2015/02/15/zhuang-shi-qi-yu-duo-jin-cheng-yi-ji-pickle/
https://stackoverflow.com/questions/9336646/python-decorator-with-multiprocessing-fails

multiprocessing是python常用的多进程模块,可以最大化的发挥机器性能。
经常会计算函数运行耗时,用到装饰器。
但在multiprocessing中运行带装饰器的函数时,就会报错,涉及到了Pickle的问题。

根据参考资料,多进程时,对象及数据是需要序列化反序列化传递的。而python常见的序列化方式就是Pickle。由参考链接可以知道,不是所有的对象(及函数)都可以Pickle序列化。Pickle序列化需要满足几个需求,详情文档。其中比较重要的一个就是,被序列化的对象要在模块顶层定义。
例如我们常见的计时装饰器方法如下:

def time_elapse(fn):
    def _wrapper(*args, **kwargs):
        start = time.perf_counter_ns()
        fn(*args, **kwargs)
        print(f"{fn.__name__} cost {(time.perf_counter_ns() - start)/1_000_000_000} s")
    return _wrapper

@time_elapse
def f():
	print("f")

f.__dict__
# 输出为{}

由于f__dict__属性在被装饰器修饰后,并不在顶层,所以无法通过__dict__属性正确反序列化。
此时我们换另一种方式,使用类装饰器,写法如下:

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

    def __call__(self, *args, **kwargs):
        start = time.perf_counter_ns()
        self.func(*args, **kwargs)
        print(
            f"{self.func.__name__} cost {(time.perf_counter_ns() - start)/1_000_000_000} s")

def f():
	print("f")
f1 = TimeElapse(f)
f1.__dict__
# 输出为{'func': <function __main__.f()>}

由此可知,经过类装饰器的修饰后,__dict__是可以准确的存储并还原信息的,所以Pickle序列化能成功。

结论

multiprocessing的进程操作设计Pickle序列化,而函数装饰器的结构特点导致Pickle序列化失败。通过改用类装饰器,可以解决Pickle序列化失败的问题。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值