Numba是Python的即时编译器,它最适用于使用NumPy数组和函数以及循环的代码。使用Numba的最经常使用方法是经过其装饰器集合,能够应用于您的函数来指示Numba编译它们。当调用Numba修饰函数时,它被编译为机器代码“及时”执行,而且您的所有或部分代码随后能够以本机机器代码速度运行!html
开箱即用的Numba使用如下方法:python
Numba可做为畅达包为 蟒蛇Python发布:git
$ conda install numba
Numba还有pip可供选择:github
$ pip install numba
Numba也能够 从源代码编译,虽然咱们不建议首次使用Numba用户。数组
Numba一般用做核心包,所以其依赖性保持在绝对最小值,可是,能够按以下方式安装额外的包以提供其余功能:缓存
scipy
- 支持编译numpy.linalg
功能。colorama
- 支持回溯/错误消息中的颜色突出显示。pyyaml
- 经过YAML配置文件启用Numba配置。icc_rt
- 容许使用Intel SVML(高性能短矢量数学库,仅限x86_64)。安装说明在 性能提示中。这取决于你的代码是什么样的,若是你的代码是以数字为导向的(作了不少数学运算),常用NumPy和/或有不少循环,那么Numba一般是一个不错的选择。在这些例子中,咱们将应用最基本的Numba的JIT装饰器,@jit
试图加速一些函数来演示哪些有效,哪些无效。架构
Numba在代码看起来像这样:app
from numba import jit import numpy as np x = np.arange(100).reshape(10, 10) @jit(nopython=True) # Set "nopython" mode for best performance def go_fast(a): # Function is compiled to machine code when called the first time trace = 0 for i in range(a.shape[0]): # Numba likes loops trace += np.tanh(a[i, i]) # Numba likes NumPy functions return a + trace # Numba likes NumPy broadcasting print(go_fast(x))
对于看起来像这样的代码,若是有的话,它将没法正常工做:函数
from numba import jit import pandas as pd x = {'a': [1, 2, 3], 'b': [20, 30, 40]} @jit def use_pandas(a): # Function will not benefit from Numba jit df = pd.DataFrame.from_dict(a) # Numba doesn't know about pd.DataFrame df += 1 # Numba doesn't understand what this is return df.cov() # or this! print(use_pandas(x))
请注意,Numba不理解Pandas,所以Numba只是经过解释器运行此代码,但增长了Numba内部开销的成本!oop
nopython
模式?Numba @jit
装饰器从根本上以两种编译模式运行, nopython
模式和object
模式。在go_fast
上面的例子中, nopython=True
在@jit
装饰器中设置,这是指示Numba在nopython
模式下操做。nopython
编译模式的行为本质上是编译装饰函数,以便它彻底运行而不须要Python解释器的参与。这是使用Numba jit
装饰器的推荐和最佳实践方式,由于它能够带来最佳性能。
若是编译nopython
模式失败,Numba能够编译使用 ,若是没有设置,这是装饰器的 后退模式(如上例所示)。在这种模式下,Numba将识别它能够编译的循环并将它们编译成在机器代码中运行的函数,而且它将运行解释器中的其他代码。为得到最佳性能,请避免使用此模式objectmode
@jit
nopython=True
use_pandas
首先,回想一下,Numba必须为执行函数的机器代码版本以前给出的参数类型编译函数,这须要时间。可是,一旦编译完成,Numba会为所呈现的特定类型的参数缓存函数的机器代码版本。若是再次使用相同的类型调用它,它能够重用缓存的版本而没必要再次编译。
测量性能时,一个很是常见的错误是不考虑上述行为,并使用一个简单的计时器来计算一次,该计时器包括在执行时编译函数所花费的时间。
例如:
from numba import jit import numpy as np import time x = np.arange(100).reshape(10, 10) @jit(nopython=True) def go_fast(a): # Function is compiled and runs in machine code trace = 0 for i in range(a.shape[0]): trace += np.tanh(a[i, i]) return a + trace # DO NOT REPORT THIS... COMPILATION TIME IS INCLUDED IN THE EXECUTION TIME! start = time.time() go_fast(x) end = time.time() print("Elapsed (with compilation) = %s" % (end - start)) # NOW THE FUNCTION IS COMPILED, RE-TIME IT EXECUTING FROM CACHE start = time.time() go_fast(x) end = time.time() print("Elapsed (after compilation) = %s" % (end - start))
这,例如打印:
Elapsed (with compilation) = 0.33030009269714355
Elapsed (after compilation) = 6.67572021484375e-06
衡量Numba JIT对您的代码的影响的一个好方法是使用timeit模块函数来执行时间,这些函数测量屡次执行迭代,所以能够在第一次执行时适应编译时间。
做为旁注,若是编译时间成为问题,Numba JIT支持 编译函数的磁盘缓存,而且还具备Ahead-Of-Time编译模式。
假设Numba能够在nopython
模式下运行,或者至少编译一些循环,它将针对您的特定CPU进行编译。加速因应用而异,但能够是一到两个数量级。Numba有一个 性能指南,涵盖了得到额外性能的经常使用选项。
Numba读取装饰函数的Python字节码,并将其与有关函数输入参数类型的信息相结合。它分析并优化您的代码,最后使用LLVM编译器库生成函数的机器代码版本,根据您的CPU功能量身定制。每次调用函数时都会使用此编译版本。
Numba有至关多的装饰,咱们看到@jit
和@njit
,但也有:
@vectorize
- 生成NumPy ufunc
(ufunc
支持全部方法)。文件在这里。@guvectorize
- 产生NumPy广义ufunc
s。 文件在这里。@stencil
- 将函数声明为相似模板操做的内核。 文件在这里。@jitclass
- 对于jit感知类。文件在这里。@cfunc
- 声明一个函数用做本机回调(从C / C ++等调用)。文件在这里。@overload
- 注册您本身的函数实现,以便在nopython模式下使用,例如@overload(scipy.special.j0)
。 文件在这里。一些装饰者提供额外选项:
ctypes / cffi / cython互操做性:
Numba能够针对Nvidia CUDA和(实验性)AMD ROC GPU。您可使用纯Python编写内核,让Numba处理计算和数据移动(或明确地执行此操做)。单击关于CUDA或ROC的 Numba文档 。
示例:接下来咱们写一段简单的代码,来计算一下执行时间:
示例1:不使用numba的:
import time def num(): arr = [] for i in range(10000000): arr.append(i) stime = time.time() num() etime = time.time() - stime # print(arr) print('用时:{}秒'.format(etime))
示例输出时间:
用时:1.4500024318695068秒
示例2:使用numba @jit
import time from numba import jit @jit def num(): arr = [] for i in range(10000000): arr.append(i) stime = time.time() num() etime = time.time() - stime # print(arr) print('用时:{}秒'.format(etime))
示例输出:
用时:0.5530002117156982秒
结论:
上述两个示例代码,一个使用了numba,另外一个没有使用numba;能够看出使用numba @jit装饰后,时间明显快了不少倍。
这只是一个简单示例;对于复杂计算提升速度更明显。