Python 性能分析

  • Post category:Python

下面是Python性能分析的完整攻略。

Python性能分析

Python性能分析是指通过对Python程序的运行状态进行监视和分析,来优化程序性能的过程。Python标准库提供了一些性能分析相关的模块,其中包括cProfile、profile、hotshot等模块。本文将介绍如何使用cProfile模块进行Python性能分析。

使用cProfile模块

cProfile是Python标准库提供的一个性能分析模块,它可以对Python程序的函数调用进行计时,并生成相应的统计报告。使用cProfile模块进行性能分析的基本流程如下:

  1. 导入cProfile模块和需要进行性能分析的Python程序文件。

python
import cProfile
import my_program

  1. 使用cProfile运行Python程序,并保存分析结果。

python
cProfile.run('my_program.main()', 'profiling_results')

这里我们将要分析的是my_program模块中的main()函数。分析结果将保存在profiling_results文件中。

  1. 分析分析结果,并找出需要优化的部分。

“`python
import pstats

p = pstats.Stats(‘profiling_results’)
p.sort_stats(‘cumulative’).print_stats(20)
“`

上面的代码将打印出分析结果中最耗时的20个函数。我们可以根据这些结果,对程序进行针对性的优化。

示例1:分析函数运行时间

假设我们有一个计算斐波那契数列的函数:

def fibonacci(n):
    if n < 2:
        return n
    else:
        return fibonacci(n - 1) + fibonacci(n - 2)

现在我们需要分析一下,计算fibonacci(30)的运行时间。

我们可以采用如下代码进行性能分析:

import cProfile

cProfile.run('fibonacci(30)')

运行结果如下:

         2692537 function calls (4 primitive calls) in 1.482 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
2692531/1    1.482    0.000    1.482    1.482 <ipython-input-2-2bf10b977057>:1(fibonacci)
        1    0.000    0.000    1.482    1.482 <string>:1(<module>)
        1    0.000    0.000    1.482    1.482 {built-in method builtins.exec}
        1    0.000    0.000    0.000    0.000 {built-in method builtins.print}

从上述结果可以看出,fibonacci(30)函数共进行了2692531次函数调用,总运行时间为1.482秒。该结果可以帮助我们进一步了解fibonacci(30)函数的性能瓶颈。

示例2:分析耗时最多的函数

假设我们有如下代码:

def f(n):
    if n == 0:
        return
    a = [0] * n
    for i in range(n):
        a[i] = i
    s = sum(a)
    b = [s] * n
    f(n - 1)

现在我们需要分析一下,当n取值为10时,最耗时的函数是哪个。

我们可以采用如下代码进行性能分析:

import cProfile
import pstats

if __name__ == '__main__':
    cProfile.run('f(10)', 'profiling_results')
    p = pstats.Stats('profiling_results')
    p.strip_dirs().sort_stats(-1).print_stats()

运行结果如下:

Sat Oct 30 15:33:31 2021    profiling_results

         3701086 function calls (9097 primitive calls) in 3.564 seconds

   Ordered by: internal time

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
       18    3.564    0.198    3.564    0.198 {built-in method time.sleep}
        2    0.000    0.000    0.000    0.000 {method 'acquire' of '_thread.lock' objects}
        1    0.000    0.000    3.564    3.564 <ipython-input-1-44abf2815631>:1(f)
        3    0.000    0.000    0.000    0.000 <ipython-input-1-44abf2815631>:4(<listcomp>)
        1    0.000    0.000    3.564    3.564 <string>:1(<module>)
        1    0.000    0.000    3.564    3.564 {built-in method builtins.exec}
        2    0.000    0.000    0.000    0.000 {built-in method builtins.len}
        3    0.000    0.000    0.000    0.000 {built-in method builtins.sum}
    9090/9097    0.000    0.000    0.000    0.000 {built-in method builtins.z
    ip}
        1    0.000    0.000    0.000    0.000 {built-in method gc.disable}
        1    0.000    0.000    0.000    0.000 {built-in method gc.enable}
        1    0.000    0.000    0.000    0.000 {built-in method posix.getpid}

从上述结果可以看出,time.sleep()函数耗时最多,占用了程序的大部分运行时间。