今天意外的发现了python装饰器和多进程之间的一个小坑,起初简单写了一个装饰器,用来给程序计时,自测了下没有什么问题
def times_used(*dargs): def time_(f): def count_time(*args, **kw): start = datetime.datetime.now() print("【{}】开始时间为:{}".format(dargs, start.strftime('%Y-%m-%d %H:%M:%S'))) f_res = f(*args, **kw) end = datetime.datetime.now() interval = (end - start).seconds times = datetime.timedelta(seconds=interval) print("【{}】结束时间:{},耗时{}".format(dargs, end.strftime('%Y-%m-%d %H:%M:%S'), times)) return f_res return count_time return time_ @times_used('哈哈') def haha(name): time.sleep(1) print("hello {}".format(name)) if __name__ == '__main__': haha("world")
输出也正常:
然后就准备把它加入我遍历文件夹模块。但是加入到模块里以后开始报错:
这里我查了很久,最后发现了问题是由于python的多进程导致的,多进程获取返回值是需要序列化的,但是装饰器是无法序列化的,所以报错。查阅资料找到解决办法为:functools.wraps,它可以解除这种束缚,从而变的可序列化。代码如下:
def times_used(*dargs):
def time_(f):
@wraps(f)
def count_time(*args, **kw):
start = datetime.datetime.now()
print("【{}】开始时间为:{}".format(dargs, start.strftime('%Y-%m-%d %H:%M:%S')))
f_res = f(*args, **kw)
end = datetime.datetime.now()
interval = (end - start).seconds
times = datetime.timedelta(seconds=interval)
print("【{}】结束时间:{},耗时{}".format(dargs, end.strftime('%Y-%m-%d %H:%M:%S'), times))
return f_res
return count_time
return time_
这样在运行就不会再报错了。
参考资料:http://gael-varoquaux.info/programming/decoration-in-python-done-right-decorating-and-pickling.html