前言
Python 虽然写起来代码量要远少于如 C++,Java,但运行速度又不如它们,因此也有了各种提升 Python 速度的方法技巧,这次要介绍的是用 Numba 库进行加速比较耗时的循环操作以及 Numpy 操作。
在 24式加速你的Python中介绍对循环的加速方法中,一个办法就是采用 Numba
加速,刚好最近看到一篇文章介绍了利用 Numba
加速 Python ,文章主要介绍了两个例子,也是 Numba
的两大作用,分别是加速循环,以及对 Numpy
相比其他语言,Python 确实在运行速度上是比较慢的。
一种常用解决方法,就是用如 C++ 改写代码,然后用 Python 进行封装,这样既可以实现 C++ 的运行速度又可以保持在主要应用中采用 Python 的方便。
这种办法的唯一难点就是改写为 C++ 部分的代码需要耗费不少时间,特别是如果你对 C++ 并不熟悉的情况。
Numba
Numba 简介
Numba
是一个可以将 Python 代码转换为优化过的机器代码的编译库。通过这种转换,对于数值算法的运行速度可以提升到接近 C
采用 Numba
并不需要添加非常复杂的代码,只需要在想优化的函数前 添加一行代码,剩余的交给 Numba
Numba
可以通过 pip
Numba
对于有许多数值运算的,Numpy
加速 Python 循环
Numba
首先,如果你想使用循环操作,你先考虑是否可以采用 Numpy
中的函数替代,有些情况,可能没有可以替代的函数。这时候就可以考虑采用 Numba
第一个例子是通过插入排序算法来进行说明。我们会实现一个函数,输入一个无序的列表,然后返回排序好的列表。
我们先生成一个包含 100,000 个随机整数的列表,然后执行 50 次插入排序算法,然后计算平均速度。
代码如下所示:
输出结果:
从代码可以知道插入排序算法的时间复杂度是 ,因为这里包含了两个循环,for
循环里面带有 while
原作者采用的是电脑配置是 i7-8700k,所以其平均耗时是 3.0104s
。但这里我的电脑配置就差多了,i5-4210M 的笔记本电脑,并且已经使用了接近 4 年,所以我跑的结果是,平均耗时为 22.84s
。那么,如何采用 Numba
输出结果:
可以看到,其实只增加了两行代码,第一行就是导入 jit
接着在函数前面增加一行代码,采用装饰器
使用 jit
装饰器表明我们希望将该函数转换为机器代码,然后参数 nopython
指定我们希望 Numba
采用纯机器代码,或者有必要的情况加入部分 Python
代码,这个参数必须设置为 True
原作者得到的平均耗时是 0,1424s
,而我的电脑上则是提升到仅需 0.094s
加速 Numpy 操作
Numba
的另一个常用地方,就是加速 Numpy
这次将初始化 3 个非常大的 Numpy
数组,相当于一个图片的尺寸大小,然后采用 numpy.square()
代码如下所示:
输出结果:
当我们对 Numpy
数组进行基本的数组计算,比如加法、乘法和平方,Numpy
都会自动在内部向量化,这也是它可以比原生 Python
上述代码在原作者的电脑运行的速度是 0.002288s
,而我的电脑需要 0.04s
但即便是 Numpy
代码也不会和优化过的机器代码速度一样快,因此这里依然可以采用 Numba
输出结果:
这里采用的是 vectorize
装饰器,它有两个数参数,第一个参数是指定需要进行操作的 numpy
数组的数据类型,这是必须添加的,因为 numba
第二个参数是 target
- cpu:运行在单线程的 CPU 上
- parallel:运行在多核、多线程的 CPU
- cuda:运行在 GPU 上
parallel
选项在大部分情况是快过 cpu
,而 cuda
上述代码在原作者的电脑运行时间是 0.001196s
,提升了 2 倍左右,而我的电脑是 0.0077s
,提升了 5 倍左右速度。
小结
numba
Python
- 代码运行速度慢于
C
- 代码的地方,典型的就是循环操作
- 在同个地方重复使用同个操作的情况,比如对许多元素进行同个操作,即
numpy
- 数组的操作
而在其他情况下,Numba
并不会带来如此明显的速度提升,当然,一般情况下尝试采用 numba
最后,练习代码:
https://github.com/ccc013/Python_Notes/blob/master/Python_tips/numba_example.ipynb
关于 Python 加速的操作,你还知道其他的技巧或者方法吗,可以留言分享一下!