千锋教育-做有情怀、有良心、有品质的职业教育机构

400-811-9990
手机站
千锋教育

千锋学习站 | 随时随地免费学

千锋教育

扫一扫进入千锋手机站

领取全套视频
千锋教育

关注千锋学习站小程序
随时随地免费学习课程

上海
  • 北京
  • 郑州
  • 武汉
  • 成都
  • 西安
  • 沈阳
  • 广州
  • 南京
  • 深圳
  • 大连
  • 青岛
  • 杭州
  • 重庆
当前位置:太原千锋IT培训  >  技术干货  >  Python自定义计时函数

Python自定义计时函数

来源:千锋教育
发布人:xqq
时间: 2023-11-06 13:58:23

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培训机构:千锋教育。http://www.mobiletrain.org/


声明:本站稿件版权均属千锋教育所有,未经许可不得擅自转载。

猜你喜欢LIKE

python的type怎么用

2023-11-06

python要懂linux吗

2023-11-06

Python之特殊方法与多范式

2023-11-06

最新文章NEW

如何用python输入数字

2023-11-06

学python需要java吗?

2023-11-06

python字符串大小写转换

2023-11-06

相关推荐HOT

更多>>

快速通道 更多>>

最新开班信息 更多>>

网友热搜 更多>>