资讯专栏INFORMATION COLUMN

教你3个python「性能分析」工具,再也不用自己计算函数耗时了

OBKoro1 / 1630人阅读

摘要:有很多性能分析工具,功能强大,可以帮助我们对各种函数的性能进行分析。这篇文章就介绍三种简单的性能分析工具。小结本文整理了三个常用的性能分析工具,帮助你定位程序的性能瓶颈。

引言

如果你想优化python程序的运行效率,你会从哪里下手?

首先,我们要找到「性能瓶颈」,比如哪些函数的运行效率低、计算时间长,然后分析原因,针对性地进行优化。

最朴素的方法是,在你预估的函数前后加上time.perf_counter()1,然后得出这个函数的运行时间。但这种方法不适用于具有大量函数调用的程序。

import timestart = time.perf_counter()func()print("cost %s second" % (time.perf_counter() - start))

python有很多性能分析工具,功能强大,可以帮助我们对各种函数的性能进行分析。

这篇文章就介绍三种简单的性能分析工具。其中cProfile和timeit都是python标准库中的工具,无需安装第三方库,看完本篇文章,教你快速上手。

1. cProfile:最便捷的性能分析

推荐指数: ⭐️⭐️⭐️⭐️

cProfile是python标准库中一个使用便捷、开销合理的 C 扩展,适用于分析长时间运行的程序。2

不想阅读太多细节的小伙伴,可以直接看代码,非常简单,直接在cProfile.run中输入目标函数名称:

import cProfileimport test_modulecProfile.run("test_module.func()")

在程序运行完后,就会在控制台打印test_module.func()运行的具体耗时情况:

538569 function calls (519249 primitive calls) in 71.446 seconds   Ordered by: standard name   ncalls  tottime  percall  cumtime  percall filename:lineno(function)	   44    0.002    0.000    0.197    0.004 ImageFile.py:154(load)       18    0.000    0.000    0.001    0.000 ImageFile.py:278(load_prepare)        1    0.000    0.000    0.000    0.000 ImageFile.py:30()        1    0.000    0.000    0.000    0.000 ImageFile.py:313(StubImageFile)        1    0.000    0.000    0.000    0.000 ImageFile.py:339(Parser)       13    0.001    0.000    1.348    0.104 ImageFile.py:478(_save)

每一行依次列出了各个子函数的运行分析信息:

  • ncalls
    调用次数

  • tottime
    在给定函数中花费的总时间(不包括调用子函数的时间

  • percall
    tottime除以ncalls的商

  • cumtime
    是在这个函数和所有子函数中花费的累积时间(从调用到退出)

  • percall
    是cumtime除以原始调用次数的商

  • filename:lineno(function)
    提供每个函数的各自信息

保存性能数据

如果你想保存这些性能数据,在run函数的参数中加上’restats’文件名:

cProfile.run("main()","restats")

就会保存到当前目录下的restats文件中。

查看性能数据

加载这些数据,可以进行后续的比较分析。

import pstatsfrom pstats import SortKey# 加载保存到restats文件中的性能数据p = pstats.Stats("restats")# 打印所有统计信息p.strip_dirs().sort_stats(-1).print_stats()

查看耗时最多的子函数

最常用的是,查看耗时最多的函数排序,比如前十个:

# 打印累计耗时最多的10个函数p.sort_stats(SortKey.CUMULATIVE).print_stats(10)# 打印内部耗时最多的10个函数(不包含子函数)p.sort_stats(SortKey.TIME).print_stats(10)


上面两个例子分别用到用SortKey.CUMULATIVESortKey.TIME参数。

SortKey的具体参数如下表所示3

查看特定名称函数的耗时

例如,我们在耗时排序中,发现一些加载函数的耗时较大,可以多带带统计下包含load的调用信息:

# 打印包含load的函数名的调用者统计信息p.print_callers(.5, "load")

0.5表示列表被剔除到其原始大小的50%,然后保留包含load的行:

例如,还可以查看哪些类的初始化__init__函数耗时较多:

# 按耗时排序,依次打印类的__init__方法的统计信息p.sort_stats(SortKey.CUMULATIVE).print_stats("__init__")

2. timeit:计算小代码片段的耗时

推荐指数: ⭐️⭐️

timeit适用于测量小段代码的耗时,可以在python代码中调用,也可以在命令行中调用4。timeit的设计避免了许多用于测量执行时间的常见陷阱。

测试你写的函数的运行时间:

def test():    """Stupid test function"""    L = [i for i in range(100)]if __name__ == "__main__":    import timeit    print(timeit.timeit("test()", setup="from __main__ import test"))

测试一个语句的运行时间:

$ python -m timeit "if hasattr(str, "__bool__"): pass"50000 loops, best of 5: 4.26 usec per loop

使用方式:
python -m timeit [-n N] [-r N] [-u U] [-s S] [-h] [statement ...]

  • -n N, --number=N
    执行“语句”多少次

  • -r N, --repeat=N
    重复计时器多少次(默认 5)

  • -s S, --setup=S
    最初执行一次的语句(默认pass)

  • -p, --process
    测量进程时间,而不是挂钟时间,使用time.process_time() 代替time.perf_counter(),这是默认值
    3.3 版中的新功能。

  • -u, --unit=U
    指定定时器输出的时间单位;可以选择 nsec、usec、msec 或 sec
    3.5 版中的新功能。

  • -v, --verbose
    打印原始计时结果;重复以获得更多数字精度

  • -h, --help
    打印一个简短的使用信息并退出

3. IDE中的性能分析

推荐指数: ⭐️⭐️⭐️

如果你有IDE,那么很多IDE都提供了性能分析的相关工具。

以pycharm 专业版为例,从Run中点击Profile,即可对当前python脚本进行性能分析。


程序运行结束后,pycharm会生成以下统计:

这里列出了子函数的名称、调用次数、耗时等信息,双击函数名可以查看对应源码。

小结

本文整理了三个常用的python性能分析工具,帮助你定位python程序的性能瓶颈。

如果对你有所帮助,欢迎一键三连,支持下博主。


  1. https://docs.python.org/3/library/time.html#time.perf_counter ↩︎

  2. https://docs.python.org/3/library/profile.html ↩︎

  3. https://docs.python.org/3/library/profile.html#module-pstats ↩︎

  4. https://docs.python.org/3/library/timeit.html ↩︎

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/119688.html

相关文章

  • python

    Python装饰器为什么难理解? 无论项目中还是面试都离不开装饰器话题,装饰器的强大在于它能够在不修改原有业务逻辑的情况下对代码进行扩展,权限校验、用户认证、日志记录、性能测试、事务处理、缓存等都是装饰器的绝佳应用场景,它能够最大程度地对代码进行复用。 但为什么初学者对装饰器的理解如此困难,我认为本质上是对Py… Python 实现车牌定位及分割 作者用 Python 实现车牌定位及分割的实践。 ...

    chenatu 评论0 收藏0
  • 首次公开,整理12年积累的博客收藏夹,零距离展示《收藏夹吃灰》系列博客

    摘要:时间永远都过得那么快,一晃从年注册,到现在已经过去了年那些被我藏在收藏夹吃灰的文章,已经太多了,是时候把他们整理一下了。那是因为收藏夹太乱,橡皮擦给设置私密了,不收拾不好看呀。 ...

    Harriet666 评论0 收藏0
  • 对狄克斯特拉算法的理解

    摘要:致敬首先向伟大的牛人致敬使用狄克斯特拉算法如果所示找出从起点到终点耗时最短的路径。狄克斯特拉算法思路步骤或思路如下找出最便宜的节点,即可在最短时间内前往的节点。 狄克斯特拉算法是一种实现了在有障碍物的两个地点之间找出一条最短路径的高效算法,解决了机器人学中的一个十分关键的问题,即运动路径规划问题,至今仍被广泛应用。是贪心方法(greedy method)的一个成功范例。 致敬 首先向伟...

    chuyao 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<