Python 性能分析方法
我想从对象的角度来分析Python代码的性能。比如说:
foo = Foo()
profiled_foo = add_profiling(foo)
# use profiled_foo like foo
...
# later
profiled_foo.print_profile()
我想知道每个方法被调用的次数,以及每个方法花费的总时间。我没有找到类似的工具,虽然我觉得写一个应该不太难。
有没有这样的库呢?或者说可能没有,因为这样分析性能可能不是个好主意?
根据Paul McGuire的回答:
import inspect
from time import sleep
from profilehooks import profile
class Foo(object):
def a(self):
sleep(0.1)
def b(self):
sleep(0.3)
def c(self):
sleep(0.5)
def add_profiling(obj):
for k in dir(obj):
attr = getattr(obj, k)
if inspect.ismethod(attr) and k != '__init__':
setattr(obj, k, profile(attr))
if __name__ == '__main__':
foo = Foo()
add_profiling(foo)
foo.a()
foo.a()
foo.b()
foo.b()
foo.a()
foo.c()
.
*** PROFILER RESULTS ***
c (oprof.py:13)
function called 1 times
3 function calls in 0.501 CPU seconds
Ordered by: cumulative time, internal time, call count
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 0.501 0.501 oprof.py:13(c)
1 0.501 0.501 0.501 0.501 {time.sleep}
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
0 0.000 0.000 profile:0(profiler)
...
3 个回答
你可以查看这个链接:http://docs.python.org/library/profile.html
在我个人看来,cProfile 是一个更直观、更快速的 Python 性能分析工具。
如果你想分析一个单独的类,可以写一个简单的测试脚本,然后用 cProfile 来运行它。
你可能听说过这个,但有个区别,就是单纯的性能分析和为了让代码运行得更快而进行的性能分析。
你想要每个方法在所有调用中的累计时间,这很好,因为如果你把这个时间除以总执行时间,就能得到这个方法占用了多少时间的百分比。如果有什么可以改进的地方,通常就是那些占比高的方法。
比起知道哪些方法占用了较高的累计时间,知道哪些代码行占用了较高的累计时间更好。这是因为如果你想在一个方法里找出问题所在,你需要关注那些占比高的具体代码行。所以如果你的性能分析工具告诉你这些代码行在哪里,你就能更精确地找到问题。
更进一步,知道这些高占比代码行的执行上下文会更有帮助。
有些人认为准确的时间测量是必要的。然而,一旦你找到了一行代码,明显可以通过改进来提高速度,比如说去掉、替换或以不同方式处理这行代码,节省的时间占总时间的比例很大,那你觉得这个比例的估算是否有点偏差真的重要吗?假设你发现那行代码占用了50%的时间。如果实际修复后节省的时间只有30%或者多到70%,你会觉得花时间去修复它是浪费吗?
这就是我鼓励使用堆栈采样的原因,这里有一个小例子。
堆栈采样自动给你每行代码的百分比,因为一行代码的百分比成本就是包含它的样本的百分比。它们还自动包括了被阻塞的时间,比如输入输出,这些信息是你需要知道的,因为它们会影响总时间。如果采样数量达到100个或1000个,你就能获得高精度的测量,但一些简单的统计证明,对于除了最小的问题外,少量的样本就足以精确定位问题。最后,样本中的上下文可以告诉你一行代码是否被合理使用。许多性能分析工具会把样本混合在一起以获得数字,但不让用户看到代表性的样本。因此,他们往往假设“热点”代码行是必要的,而实际上上下文可能会告诉他们并非如此。
这里有一个更详细的问题列表。
我在使用这些装饰器时取得了不错的效果:http://mg.pov.lt/profilehooks/