大家都知道,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 这个是新版本