Python 性能分析之每行耗时 line_profiler

大家都知道,Python 的运算性能不是很强,所以才有了那么多用 C/C++ 来计算的第三方 Python 包,还有各种各样的加速实践。

那么,应该加速哪些代码呢?我之前一般用自带的 cProfile,然而它的输出确实不是太好看,夹杂了非常多无用的信息。

最近才发现了 line_profiler 这个第三方扩展,用起来比 cProfile 直观很多。

安装

pip install line-profiler

安装需要编译器。如果在 Windows 平台,需要自行先安装 C++ 编译器。如果不想装麻烦的 VC++,可以转而在 这里 下载别人编译好的 .whl 安装包。在 Linux/Mac 上面就简单很多,编译环境肯定有的。 最近发现新版的已经不需要了,Windows 也有了编译好的包,可以直接安装。

使用

在需要 profile 的函数前,加上”@profile”,例如下面的 xxxxxx.py:

@profile
def main():
    l = [i for i in range(10000)]
    s = set(l)

    for _ in range(1000):
        if 9876 in l:
            pass
        if 9876 in s:
            pass

if __name__ == '__main__':
    main()

这个”@profile”只是一个标记,不是 Python 的语句,所以会导致代码不能直接运行,只能用专门的方法运行(下面有),这不是太方便(目前的版本是这样)。

经过一点使用,了解到 @profile 的用法有一点限制,不可以对 class 打标签,但是可以打在 class 的方法上;子函数也可以用;并且可以同时 profile 多个函数 。

然后,运行:

kernprof -v -l xxxxxx.py

我们就得到了结果:

Wrote profile results to xxxxxx.py.lprof
Timer unit: 1e-06 s

Total time: 0.076552 s
File: xxxxxx.py
Function: main at line 2

Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
     2                                           @profile
     3                                           def main():
     4         1        965.0    965.0      1.3      l = [i for i in range(10000)]
     5         1        792.0    792.0      1.0      s = set(l)
     6
     7      1001       1278.0      1.3      1.7      for _ in range(1000):
     8      1000      71133.0     71.1     92.9          if 9876 in l:
     9                                                       pass
    10      1000       1297.0      1.3      1.7          if 9876 in s:
    11      1000       1087.0      1.1      1.4              pass

可以发现,第 8 行的地方,无论是每次运行(Per Hit),还是总耗时(% Time),都占用了大量的时间。所以就改为第 10 行的用法,马上快了几十倍。

参考

1. https://github.com/rkern/line_profiler
2. https://github.com/pyutils/line_profiler 这个是新版本


发表评论