Python 性能分析方法

3 投票
3 回答
2316 浏览
提问于 2025-04-17 04:58

我想从对象的角度来分析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 个回答

1

你可以查看这个链接:http://docs.python.org/library/profile.html

在我个人看来,cProfile 是一个更直观、更快速的 Python 性能分析工具。

如果你想分析一个单独的类,可以写一个简单的测试脚本,然后用 cProfile 来运行它。

1

你可能听说过这个,但有个区别,就是单纯的性能分析和为了让代码运行得更快而进行的性能分析。

你想要每个方法在所有调用中的累计时间,这很好,因为如果你把这个时间除以总执行时间,就能得到这个方法占用了多少时间的百分比。如果有什么可以改进的地方,通常就是那些占比高的方法。

比起知道哪些方法占用了较高的累计时间,知道哪些代码行占用了较高的累计时间更好。这是因为如果你想在一个方法里找出问题所在,你需要关注那些占比高的具体代码行。所以如果你的性能分析工具告诉你这些代码行在哪里,你就能更精确地找到问题。

更进一步,知道这些高占比代码行的执行上下文会更有帮助。

有些人认为准确的时间测量是必要的。然而,一旦你找到了一行代码,明显可以通过改进来提高速度,比如说去掉、替换或以不同方式处理这行代码,节省的时间占总时间的比例很大,那你觉得这个比例的估算是否有点偏差真的重要吗?假设你发现那行代码占用了50%的时间。如果实际修复后节省的时间只有30%或者多到70%,你会觉得花时间去修复它是浪费吗?

这就是我鼓励使用堆栈采样的原因,这里有一个小例子

堆栈采样自动给你每行代码的百分比,因为一行代码的百分比成本就是包含它的样本的百分比。它们还自动包括了被阻塞的时间,比如输入输出,这些信息是你需要知道的,因为它们会影响总时间。如果采样数量达到100个或1000个,你就能获得高精度的测量,但一些简单的统计证明,对于除了最小的问题外,少量的样本就足以精确定位问题。最后,样本中的上下文可以告诉你一行代码是否被合理使用。许多性能分析工具会把样本混合在一起以获得数字,但不让用户看到代表性的样本。因此,他们往往假设“热点”代码行是必要的,而实际上上下文可能会告诉他们并非如此。

这里有一个更详细的问题列表

6

我在使用这些装饰器时取得了不错的效果:http://mg.pov.lt/profilehooks/

撰写回答