Python 应用剖析工具介绍(python和java哪个更值得学)

网友投稿 658 2022-09-24

本站部分文章、图片属于网络上可搜索到的公开信息,均用于学习和交流用途,不能代表睿象云的观点、立场或意见。我们接受网民的监督,如发现任何违法内容或侵犯了您的权益,请第一时间联系小编邮箱jiasou666@gmail.com 处理。

Python 应用剖析工具介绍(python和java哪个更值得学)

工具

闲话少叙,下面开始介绍分析 Python 代码的几种便捷工具。

cProfile

CPython distribution 自带两种分析工具:profile 与 cProfile。两者使用同样的 API,按理说运行效果应该差不多。然而,前者的运行时开销更大,因此,本文将主要介绍 cProfile。

借助 cProfile,可以轻松实现对代码的深入分析,并且了解代码的哪些部分亟待提升。查看下面的缓慢代码实例:

--> % cat slow.pyimport timedef main():      sum = 0      for i in range(10):              sum += expensive(i // 2)      return sum  def expensive(t):       time.sleep(t)       return t   if __name__ == '__main__':    print(main())

在上面的代码中,笔者通过调用 time.sleep 方法,模拟一个运行时间很长的程序,并假定运行结果很重要。接下来,对这段代码进行分析,结果如下:

--> % python -m cProfile slow.py20         34 function calls in 20.030 seconds   Ordered by: standard name    ncalls  tottime  percall  cumtime  percall filename:lineno(function)         1    0.000    0.000    0.000    0.000 __future__.py:48()         1    0.000    0.000    0.000    0.000 __future__.py:74(_Feature)         7    0.000    0.000    0.000    0.000 __future__.py:75(__init__)        10    0.000    0.000   20.027    2.003 slow.py:11(expensive)         1    0.002    0.002   20.030   20.030 slow.py:2()         1    0.000    0.000   20.027   20.027 slow.py:5(main)         1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}         1    0.000    0.000    0.000    0.000 {print}         1    0.000    0.000    0.000    0.000 {range}        10   20.027    2.003   20.027    2.003 {time.sleep}

我们发现,分析结果相当琐碎。其实,可以用更有益的方式组织分析结果。在上例中,调用列表是按照字母顺序排列的,这对我们并无价值。笔者更愿意看到按照调用次数或累计运行时间排列的调用情况。幸运的是,通过 -s 参数就能实现这一点。我们马上就能看到存在问题的代码段了!

--> % python -m cProfile -s calls slow.py20         34 function calls in 20.028 seconds   Ordered by: call count         ncalls  tottime  percall  cumtime  percall filename:lineno(function)          10    0.000    0.000   20.025    2.003 slow.py:11(expensive)          10   20.025    2.003   20.025    2.003 {time.sleep}           7    0.000    0.000    0.000    0.000 __future__.py:75(__init__)           1    0.000    0.000   20.026   20.026 slow.py:5(main)           1    0.000    0.000    0.000    0.000 __future__.py:74(_Feature)           1    0.000    0.000    0.000    0.000 {print}           1    0.000    0.000    0.000    0.000 __future__.py:48()           1    0.003    0.003   20.028   20.028 slow.py:2()           1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}           1    0.000    0.000    0.000    0.000 {range}

果然!我们发现,存在问题的代码就在 expensive 函数当中。该函数在执行结束之前调用了多次 time.sleep 方法,因此导致了程序的速度下降。

基本功能介绍完毕之后,让我们来看看使用分析工具查找问题代码的其他方法。

PyCallGraph

-> % pip install pycallgraph

通过下面的指令,就能运行图形化应用:

-> % pycallgraph graphviz -- python slow.py

运行完毕之后,在运行脚本的目录下会出现一张 pycallgraph.png 图片文件。同时,还应该得到相似的分析结果(如果你之前已经用 cProfile 分析过了)。结果中的数据应该与 cProfile 提供的结果一致。不过,PyCallGraph 的优点在于,它能展示被调用函数相互间的关系。

让我们来看看图片到底长什么样:

这多方便啊!图片显示了程序的运行路径,告诉我们程序经历过的每个函数、模块以及文件,还带有运行时间与调用次数等信息。如果在庞大的应用中运行该分析工具,会得到一张巨大的图片。但是,根据颜色的差别,我们仍能轻易找到存在问题的代码块。下面是 PyCallGraph 文档中提供的一张图片,展示了一段复杂的正则表达式调用中代码的运行路径:

这些信息有什么用?

一旦我们确定了导致问题代码的根源,就可以选择合适的解决方案优化代码,为其提速。下面,让我们根据特定的情况,探讨一些缓慢代码可行的解决方案。

I/O

正则表达式

人们都说,一旦你决定用正则表达式解决某个问题,你就有两个问题要解决了。正则表达式真的很难用对,而且难以维护。关于这一点,笔者可以写一篇长篇大论进行阐述。(但是,我不会写的:)。正则表达式真的不简单,我相信有很多博文已经做了详尽的阐述。)不过,在此,笔者将介绍几个有用的技巧:

以上是有关正则表达式笔者想说的全部内容。如果你想要更多信息,相信网络上还有很多好的文章。

Python 代码

from functools import wrapsdef memoize(f):    cache = {}        @wraps(f)        def inner(arg):              if arg not in cache:            cache[arg] = f(arg)               return cache[arg]        return inner

import time@memoizedef slow(you):    time.sleep(3)    print("Hello after 3 seconds, {}!".format(you))        return 3

现在,如果我们多次运行该函数,运行结果就会立即出现:

>>> slow("Davis")Hello after 3 seconds, Davis!3>>> slow("Davis")3>>> slow("Visitor")Hello after 3 seconds, Visitor!3>>> slow("Visitor")3

对于该项目来说,这是极大的速度提升。而且代码运行起来也没有出现故障。

其他情况

如果你的代码无法使用记忆(memoization)技巧,你的算法也不像 O(n!) 这样疯狂,或者代码的剖析结果也没有引人注意的地方,这可能说明你的代码并不存在显著的问题。这时候,你可以尝试一下别的运行环境或语言。PyPy 就是一个好的选择,你可能还要将算法用C语言扩展方法重写一下。幸运的是,笔者之前的项目并未走到这一步,但是这仍是很好的排错方案。

结论

剖析代码可以帮助你理解项目的执行流程、找出潜在的问题代码,以及作为开发者该如何提升程序运行速度。Python 剖析工具不但功能强大,简单易用,而且足够深入以快速找出问题根源。虽然 Python 并不是以快速著称的语言,但这并不意味着你的代码应该拖拖拉拉。管理好自己的算法,适时进行剖析,但绝不要过早优化!

上一篇:如何更早地发现 DDoS 攻击?(如何做到早发现)
下一篇:4 招教你如何在应用商店脱颖而出(4399在线观看免费观看电影)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~