用于编解码的一个公共库脚本慢的实在是不行,以前对python不熟,唯一熟悉的优化方式就是用c++写so给python加扩展,当时勉强就用了;现在时间稍微有点闲的时候,网上刚好看到一篇 python 优化的文章,其中介绍了profile等分析器的使用,技痒之余,想拿个现成的来练练手,回想起那个恶心的慢的离谱的编解码,不正是练手的最好材料么;
呃,不用不知道,一用吓一条,脚本调用命令为:
python -m profile -s time ./xx.py get_list 2895300 / 1
照常的慢,于是去外面活动了下,回来发现终于完成了,输出如下:
2133518 function calls (2132822 primitive calls) in 285.050 CPU seconds
Ordered by: internal time
ncalls tottime percall cumtime percall filename:lineno(function)
599071 275.190 0.000 275.190 0.000 TSTransport.py:35(readAll)
6932 1.970 0.000 284.580 0.041 ttypes.py:118(read)
521369 1.700 0.000 1.700 0.000 :0(unpack)
242628 1.540 0.000 121.100 0.000 TBinaryProtocol.py:192(readByte)
159443 1.170 0.000 79.280 0.000 TBinaryProtocol.py:197(readI16)
166375 1.130 0.000 163.180 0.001 TBinaryProtocol.py:151(readFieldBegin)
112364 0.760 0.000 56.420 0.001 TBinaryProtocol.py:202(readI32)
总共花了 285s,其中有个调用竟然花了 275s...,迅速找到这段代码,里面是:
-
buff = self.__buf[0:sz]
-
self.__buf = self.__buf[sz:]
-
#print "All read:%d ,left:%d" % (sz, len(self.__buf))
-
return buff
仔细一想,这代码当初是怎么写的,这不是疯狂的memcpy么?于是改成了:
-
new_pos = self.__read_pos + sz
-
buff = self.__buf[self.__read_pos:new_pos]
-
self.__read_pos = new_pos
-
#print "All read:%d ,left:%d" % (sz, len(self.__buf))
-
return buff
然后再跑一次,很快就完成了,输出如下:
2133515 function calls (2132819 primitive calls) in 10.270 CPU seconds
Ordered by: internal time
ncalls tottime percall cumtime percall filename:lineno(function)
599071 1.690 0.000 1.690 0.000 TSTransport.py:39(readAll)
242628 1.540 0.000 2.780 0.000 TBinaryProtocol.py:192(readByte)
521369 1.470 0.000 1.470 0.000 :0(unpack)
6932 1.430 0.000 9.750 0.001 ttypes.py:118(read)
足足降低了28倍...
分析问题,解决问题;这才是问题解决之道!不要依赖直觉,而应该靠分析,靠数据!
阅读(3314) | 评论(0) | 转发(1) |