在我们遇到性能问题的时候,很多时候需要去查看性能的瓶颈在哪里,本篇文章就是提供了多种常用的方案来监控函数的运行时间。
1.time
首先说明,time模块很多是系统相关的,在不同的OS中可能会有一些精度差异,如果需要高精度的时间测量,可以使用time.perf_counter。perf_counter仍然还是 基于时钟时间,很多因素会影响到它的精确度,比如机器负载。如果你对于执行时间更感兴趣,使用 time.process_time() 来代替它。 更多内容可以参考尾部的链接。
下面两个例子来源于《python cookbook》
装饰器模式1
装饰函数,测试函数运行时间
importtimefromfunctoolsimportwrapsdeftimethis(func):Decorator that reports the execution time.@wraps(func)defwrapper(*args,**kwargs):start=time.perf_counter()result=func(*args,**kwargs)end=time.perf_counter()print(func.__name__,end-start)returnresultreturnwrapper@timethisdefcountdown(n):"""Counts down"""whilen>0:n-=1countdown(100000)
装饰器模式2
上下文管理器,测试代码片运行时间
importtimefromcontextlibimportcontextmanager@contextmanagerdeftimethis(label):start=time.perf_counter()try:yieldfinally:end=time.perf_counter()print({}: {}.format(label,end-start))Example usewithtimethis(counting):n=10000000whilen>0:n-=1
2.timeit
python提供了timeit模块,这个可以在python console中直接使用
$python-mtimeit-n4-r5-s"import timing_functions""timing_functions.random_sort(2000000)"
输出为:
4loops,bestof5:2.08secperloop
timeit在notebook中的使用
这个模块在ipython中使用起来相对简洁很多。
- %timeit, 这种方式可以测量单行代码。
- %%timeit, 这种方式可以测量整个cell的代码。
3.cprofile
上面的方法其实还是比较简单粗暴。profile模块是个更好的cProfile是profile的C实现,速度会更快。类似的包有pickle,也有个对应的Cpickle版本。 这个包可嵌入的代码中,类似下面这种:
importcProfilecProfile.run("myfunction()")
我个人最喜欢的还是下面这种(下面的代码可能需要加一下PYTHONPATH):
$python -m cProfile -o output.pkl my_main_file.py
首先无需更改现有代码结构,其次可以将结果保存到output.pkl中。强烈建议将profile的结果保存起来,因为生产中有些profile可能耗时很长,而且控制台输出的内容有限,当你想从结果里面提取点重要信息,又要重新来过,特别耗时。
当获取上面的output.pkl的时候,可以进入python console,使用pstats得到结果:
importpstatsp=pstats.Stats(output.pkl)文件名p.sort_stats(time)按照时间排序p.print_stats(10)最耗时的前10个,如果没有参数,默认输出全部
- ncalls: 函数被call的次数
- tottime:函数总的耗时,但是不包括其子函数的耗时
- percall:tottime平均到每次调用的耗时
- cumtime:函数总的耗时,包括了其子函数的耗时(- 递归函数也不例外)
- percall:cumtime平均到每次调用的耗时
- filename:lineno(function) :每个函数各自的信息
4.line_profiler
看每一行执行的时间占比,也大概知道原因出在什么地方了。自带的profile会深入到包的底层运算逻辑,不是特别清晰。下面是line_profiler的使用方法,个人感觉比装饰器的方式好用太多:
from line_profiler import LineProfiler
import random
def do_stuff(numbers):
s = sum(numbers)
l = [numbers[i]/43 for i in range(len(numbers))]
m = [hello+str(numbers[i]) for i in range(len(numbers))]
numbers = [random.randint(1,100) for i in range(1000)]
lp = LineProfiler()
lp_wrapper = lp(do_stuff) 函数
lp_wrapper(numbers) 参数
lp.print_stats()
line_profiler在notebook中使用
line_profiler在notebook的使用也超级方便,非常推荐。
%load_extline_profilerclassA:defto_profile_func():pass%lprun-fA.to_profile_funcA.to_profile_func()
参考链接
Difference between CPU time and wall time
stackoverflow:How to measure elapsed time in Python?
声明:本文部分素材转载自互联网,如有侵权立即删除 。
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是赞助,收取费用仅维持本站的日常运营所需!
7. 如遇到加密压缩包,请使用WINRAR解压,如遇到无法解压的请联系管理员!
8. 精力有限,不少源码未能详细测试(解密),不能分辨部分源码是病毒还是误报,所以没有进行任何修改,大家使用前请进行甄别
丞旭猿论坛
暂无评论内容