Python自定义计时函数

来源:千锋教育
发布时间:2023-11-07 04:40:39
分享

python标准库提供的cProfile/profile模块,计时输出信息较多。本节将介绍其他几种精度略低但简单易用的计时工具。根据代码粒度不同,将其分为三类。

1.1整个程序计时

Unix/Linux系统中,可用time命令简单地统计整个程序的耗时。例如:

[wangxiaoyuan_@localhostPyTest]$timepythonBCLineCounter.pybulk

FileLinesCodeLinesCommentLinesEmptyLinesCommentPercent

1545010437326425380.24

real0m2.803s

user0m1.124s

sys0m0.052s

统计值real表示程序运行的实际耗时,user表示程序执行用户态代码(内核外)耗费的CPU时间,sys表示程序在内核态运行所耗费的CPU时间(即调用特定内核函数的耗时)。若user和sys时间之和小于real时间,表明程序为I/O密集型(I/Obound),即程序的性能问题很可能与等待I/O有关。

time命令的详细描述参见《Linux用户态程序计时方式详解》。

1.2代码片段计时

代码片段计时分为函数计时和语句块计时。这两种计时均可使用Python标准库timeit模块,该模块的详细介绍参见官方帮助。

本小节将使用timeit模块的timeit()方法,即timeit(stmt='pass',setup='pass',timer=,number=1000000)。其中,参数stmt为待计时的目标代码;setup为执行代码的准备工作(通常是import之类的语句),不计入时间;timer在Windows系统中为time.clock(),Linux系统中则为time.time(),取默认值即可;number指示stmt重复执行的次数。该方法返回执行stmt代码number遍所用的时间,单位为秒,float类型。

除timeit()方法外,对于特定函数的计时,可使用装饰器(decorator);对于语句块计时,则可使用上下文管理器(contextmanager)。

以装饰器为例:

importfunctools,sys,time

defFuncTimer(repeats=10000):

defdecorator(func):

@functools.wraps(func)

defwrapper(*args,**kwargs):

#Windows系统中clock()粒度为毫秒,time()粒度为1/60秒;

#Unix系统中clock()粒度为1/100秒,time()精度较其更高。

ifsys.platform=="win32":

timerFunc=time.clock

else:

timerFunc=time.time

try:

startTime=timerFunc()

foriinrange(repeats):

ret=func(*args,**kwargs)

finally:#当目标函数发生异常时,仍旧输出计时信息

endTime=timerFunc()

print'%s.%s()=>'%(func.__module__,func.__name__),

print'TimeElasped:%.3fmsec,repeated%dtime(s).'\

%(((endTime-startTime)*1000.0),repeats)

returnret

returnwrapper

returndecorator

运行如下代码,对比自定义装饰器FuncTimer与timeit模块计时效果:

@FuncTimer(10)

defDecoratedFunc():

L=[]

foriinrange(100):L.append(i)

defRawFunc():

L=[]

foriinrange(100):L.append(i)

DecoratedFunc()

importtimeit;print'%.6fsec'%timeit.timeit(stmt=RawFunc,number=10)

输出如下:

__main__.DecoratedFunc()=>TimeElasped:0.164msec,repeated10time(s).

0.000174sec

可见,计时效果非常接近。

注意,FuncTimer装饰器内根据系统选用不同的计时器,这是考虑到time.clock()的精度因系统平台而异。在Unix/Linux系统中,该方法返回当前所耗的CPU时间;而在Windows系统中,该方法基于Win32函数QueryPerformanceCounter(),返回从首次调用待计时函数起所经历的挂钟时间(wallclocktime),精度较time.time()更高。相比而言,timeit方法中使用的缺省计时器总是测量挂钟时间,这也意味着关于某函数的计时可能会受到同一计算机上运行的其他进程的影响。

time.clock()计时器的平台差异性参考以下示例(假定所在脚本名为Timing.py):

@FuncTimer(5)

defSqrtTiming(loops):

importmath

try:

frommathimportfsum#Python2.6+

returnfsum([math.sqrt(x)forxinrange(loops)])

exceptImportError:#Python2.5-

returnsum([math.sqrt(x)forxinrange(loops)])

@FuncTimer(1)

defSleepTiming():

time.sleep(2)

file=open(r'out.txt',"w+")

foriinrange(10000):

file.write('helloworld!')

SqrtTiming(100000)

SleepTiming()

在Windows系统控制台和IDLEShell里的运行结果如下:

E:\PyTest>Timing.py

SqrtTiming()=>TimeElasped:150.124msec,repeated5time(s).

SleepTiming()=>TimeElasped:2155.140msec,repeated1time(s).

__main__.SqrtTiming()=>TimeElasped:151.809msec,repeated5time(s).

__main__.SleepTiming()=>TimeElasped:2185.594msec,repeated1time(s).

>>>importTiming

Timing.SqrtTiming()=>TimeElasped:148.892msec,repeated5time(s).

Timing.SleepTiming()=>TimeElasped:2223.157msec,repeated1time(s).

在Linux系统中运行结果与之类似。若将timerFunc改为time.clock(),则计时输出为:

[wangxiaoyuan_@localhost~]$timepythonTiming.py

__main__.SqrtTiming()=>TimeElasped:320.000msec,repeated5time(s).

__main__.SleepTiming()=>TimeElasped:330.000msec,repeated1time(s).

real0m2.381s

user0m0.332s

sys0m0.019s

可见,time.sleep(2)并未计入SleepTiming()耗时,导致计时结果与real时间相差很大。

对于代码片段计时,以上下文管理器为例:

importcontextlib,sys,time

@contextlib.contextmanager

defBlockTimer(label='Block'):

ifsys.platform=="win32":timerFunc=time.clock

else:timerFunc=time.time

startTime=timerFunc()

try:

yield

finally:

endTime=timerFunc()

print'%s=>'%label,

print'TimeElasped:%.3fmsec.'\

%((endTime-startTime)*1000.0)

基于BlockTimer测量代码片段的示例如下:

withBlockTimer('cPickle'):

fromcPickleimportdumps,loads

s=dumps([x*2.4forxinrange(100000)])

loads(s)

withBlockTimer('json'):

fromjsonimportdumps,loads

s=dumps([x*2.4forxinrange(100000)])

loads(s)

运行结果如下:

cPickle=>TimeElasped:237.569msec.

json=>TimeElasped:181.714msec.

可见,对于浮点型对象,json模块执行速度比cPickle模块更快。

当然,借助timeit模块也可对代码片段计时。例如:

fromtimeitimporttimeit

sep='fromcPickleimportdumps,loads'

stp='s=dumps([x*2forxinrange(100000)]);loads(s)'

print'cPickle:%.6fsec'%timeit(stmt=stp,setup=sep,number=1)

sej='fromjsonimportdumps,loads'

stj='s=dumps([x*2forxinrange(100000)]);loads(s)'

print'json:%.6fsec'%timeit(stmt=stj,setup=sej,number=1)

本例改为整型对象,且模块导入语句不计入总耗时。运行结果如下:

cPickle:0.100775sec

json:0.064752sec

可见,对于整型对象,json模块执行速度也比cPickle模块快。

以上内容为大家介绍了Python自定义计时函数,希望对大家有所帮助,如果想要了解更多Python相关知识,请关注IT培训机构:千锋教育。https://www.mobiletrain.org/


声明:本站部分稿件版权来源于网络,如有侵犯版权,请及时联系我们。

相关推荐

  • Python C代码统计工具代码的效果验证 为验证上篇文章的代码实现,建立lctest调试目录。该目录下包含line.c及和《为C函数自动添加跟踪语句》一文中的test.c文件。其中,line.c内容如下:#include/*{{{commen
  • python np.nonzero()函数 nonzero函数是numpy中用于得到数组array中非零元素的目录(位置)的函数。返回值为元组,两个值分别为两个维度,包含了相应维度上非零元素的目录值。只有a中非零元素才会有索引值,那些零值元素没
  • Python 分类技术 分类技术(或分类法)是一种根据输入数据建立分类模型的系统方法,分类法的例子包括决策分类法,基于规则的分类法,神经网络,支持向量机和朴素贝叶斯分类法。这些技术都使用一种学习算法(learningalgo
  • Python 决策树算法思想 决策树(decisiontree)是一个树结构(可以是二叉树或者非二叉树)。决策树分为分类树和回归树两种,分类树对离散变量做决策树,回归树对连续变量做决策树。其中每个非叶节点表示一个特征属性上的测试,
  • Python 决策树的生成算法介绍 划分数据集的最大原则是:使无序的数据变的有序。如果一个训练数据中有20个特征,那么选取哪个做划分依据?这就必须采用量化的方法来判断,量化划分方法有多重,其中一项就是“信息论度量信息分类”。基于信息论的
  • Python C4.5算法 ID3算法的作者昆兰基于上面的不足,对ID3算法做了改进,这就是C4.5算法,也许你会问,为什么不叫ID4,ID5之类的名字呢?那是因为决策树当时太火爆了,它的ID3一出来,别人二次创新,很快就占了I