26.6 测试代码性能
http://scz.617.cn/unix/201112281806.txt
A: lotrpy@weibo 2011-12-27 19:07
可以用timeit模块进行快速的性能测试:
python -m timeit -s "x=['a','b','c'];y=['d','e','f']" "[''.join(z) for z in zip(x,y)]"
100000 loops, best of 3: 2.24 usec per loop
A: scz@nsfocus
python MergeListProfile.py
#!/usr/bin/env python
import time import sys from itertools import izip
##########################################################################
def TimeOfFunction ( function, num=100000 ):
def void() :
pass
#
# end of void
#
time_a = time.clock()
for i in range( num ) :
void()
#
# end of for
#
time_b = time.clock()
time_c = time.clock()
for i in range( num ) :
function()
#
# end of function
#
time_d = time.clock()
#
# 返回函数名以及执行时间,已经考虑了调度时间。
#
return( function.__name__, ( time_d - time_c ) - ( time_b - time_a ) )
##########################################################################
"""
x = ['a','b','c'] y = ['d','e','f'] """
x = ['A' + str(i) for i in xrange(0,100)] y = ['B' + str(i) for i in xrange(0,100)]
##########################################################################
def TargetFunc_0 () : return( map((lambda x,y:x+y),x,y) )
def TargetFunc_1 () : return( [''.join(z) for z in zip(x,y)] )
def TargetFunc_2 () : ret = [] n = len( x ) for i in range( n ) : ret.append( x[i] + y[i] ) # # end of for # return( ret )
def TargetFunc_3 () : return( [v+y[i] for i,v in enumerate(x)] )
def TargetFunc_4 () : return( [x[i]+y[i] for i in range(len(x))] )
def TargetFunc_5 () : return( [i+j for i,j in zip(x,y)] )
def TargetFunc_6 () : L = len( x ) # # range()会直接生成一个list,xrange()则不会,而是每次被调用时返回其中 # 的一个值,xrange()在循环中的性能比range()好,尤其是返回很大的list时, # 尽量用xrange()。 # return( [x[i]+y[i] for i in xrange(L)] )
def TargetFunc_7 () : return( [i+j for i,j in izip(x,y)] )
##########################################################################
ret = {}
funcs =
[
TargetFunc_0,
TargetFunc_1,
TargetFunc_2,
TargetFunc_3,
TargetFunc_4,
TargetFunc_5,
TargetFunc_6,
TargetFunc_7
]
oldret = [] newret = [] for function in funcs : newret = function() if not oldret : # # 这里不需要动用copy.copy()或copy.deepcopy() # oldret = newret elif oldret != newret : print 'Checking %s()' % function.name sys.exit( -1 )
num = 10 for i in range( num ) : # print "Round[%u]" % i # for function in funcs : a, b = TimeOfFunction( function ) if a in ret : ret[a] += b else : ret[a] = b print "%s : %.9fs" % ( a, b ) # # end of for #
print 'Average:'
result = zip( ret.values(), ret.keys() )
result.sort( reverse=True ) for x in result : print "%s : %.9fs" % ( x[1], x[0] / num )
假设:
x = ['a','b','c'] y = ['d','e','f'] num = 1000000
Average: TargetFunc_2 : 2.313999329s TargetFunc_1 : 2.298966419s TargetFunc_0 : 2.185276983s TargetFunc_5 : 2.009906884s TargetFunc_4 : 1.765377419s TargetFunc_3 : 1.676222731s TargetFunc_7 : 1.586907511s TargetFunc_6 : 1.529695776s
假设:
x = ['A' + str(i) for i in xrange(0,100)] y = ['B' + str(i) for i in xrange(0,100)] num = 100000
Average: TargetFunc_1 : 3.966280626s TargetFunc_2 : 3.902535827s TargetFunc_0 : 3.218697966s TargetFunc_5 : 2.759791314s TargetFunc_3 : 2.592151199s TargetFunc_4 : 2.578258690s TargetFunc_6 : 2.572227805s TargetFunc_7 : 2.149801880s
当x、y是大list时,izip()效率优势明显,比enumerate()、xrange()都快。
A: hw@nsfocus 2012-01-09 15:10
python MergeListProfileOther.py
#!/usr/bin/env python
import sys import timeit from itertools import izip
##########################################################################
def TimeOfFunction ( fname, num=100000 ): t = timeit.Timer( '%s()' % fname, 'from main import %s' % fname ) # # 返回函数名以及执行时间。 # return( fname, t.timeit( number=num ) )
##########################################################################
"""
x = ['a','b','c'] y = ['d','e','f'] """
x = ['A' + str(i) for i in xrange(0,100)] y = ['B' + str(i) for i in xrange(0,100)]
##########################################################################
def TargetFunc_0 () : return( map((lambda x,y:x+y),x,y) )
def TargetFunc_1 () : return( [''.join(z) for z in zip(x,y)] )
def TargetFunc_2 () : ret = [] n = len( x ) for i in range( n ) : ret.append( x[i] + y[i] ) # # end of for # return( ret )
def TargetFunc_3 () : return( [v+y[i] for i,v in enumerate(x)] )
def TargetFunc_4 () : return( [x[i]+y[i] for i in range(len(x))] )
def TargetFunc_5 () : return( [i+j for i,j in zip(x,y)] )
def TargetFunc_6 () : L = len( x ) # # range()会直接生成一个list,xrange()则不会,而是每次被调用时返回其中 # 的一个值,xrange()在循环中的性能比range()好,尤其是返回很大的list时, # 尽量用xrange()。 # return( [x[i]+y[i] for i in xrange(L)] )
def TargetFunc_7 () : return( [i+j for i,j in izip(x,y)] )
##########################################################################
if 'main' == name : this = sys.modules['main'] # # 确保这些函数返回值一致。 # oldret = [] newret = [] for f in dir( this ) : if callable( getattr( this, f, None ) ) and f.startswith( 'TargetFunc_' ) : newret = eval( '%s()' % f ) if not oldret : # # 这里不需要动用copy.copy()或copy.deepcopy() # oldret = newret elif oldret != newret : print 'Checking %s()' % f sys.exit( -1 ) # # end of for # ret = {} # # 循环10次计算平均值 # num = 10 for i in range( num ) : # print "Round[%u]" % i # for f in dir( this ) : if callable( getattr( this, f, None ) ) and f.startswith( 'TargetFunc_' ) : a, b = TimeOfFunction( f ) if a in ret : ret[a] += b else : ret[a] = b print "%s : %.9fs" % ( a, b ) # # end of for # # # end of for # print 'Average:' # # 2010-12-17 15:18 scz # # 对各函数运行时间进行降序排序并输出。map()第一形参是None时相当于zip()。 # result = zip( ret.values(), ret.keys() ) # # 出于空间上的考虑,sort()直接在原list所在空间上进行排序,就是说调用结束后 # result被改变。sort()不会返回新的list。 # result.sort( reverse=True ) for x in result : print "%s : %.9fs" % ( x[1], x[0] / num ) # # end of for #
假设:
x = ['A' + str(i) for i in xrange(0,100)] y = ['B' + str(i) for i in xrange(0,100)] num = 100000
Average: TargetFunc_1 : 3.931241167s TargetFunc_2 : 3.912196821s TargetFunc_0 : 3.108840062s TargetFunc_5 : 2.775525899s TargetFunc_3 : 2.744446860s TargetFunc_4 : 2.742812149s TargetFunc_6 : 2.646931505s TargetFunc_7 : 2.190302298s
MergeListProfile.py的TimeOfFunction()是自己实现的,MergeListProfileOther.py 的TimeOfFunction()用了timeit模块。从最终结果看,自己实现的TimeOfFunction() 相比timeit模块,没有额外的效率损耗,两种办法都可以用。