The website uses cookies. By using this site, you agree to our use of cookies as described in the Privacy Policy.
I Agree

Numba 开发手册(一)

网址:http://numba.pydata.org/numba-doc/latest/user/index.html

一、5分钟quick start

Numba是一个python的即时编译器,其使用Numpy的arrays,functions和loops。当调用Numba修饰函数时,它被编译为机器代码即时执行,并且全部或部分代码随后可以以本机机器代码速度运行!(大概意思是部分代码给编译了,不是像之前一样解释运行)

注意:现在numba还在armv7l, armv8l (aarch64)平台上实验,在AMD ROC(GPU)也处于实验状态。

判断什么情况下比较适合使用Numba:

如果代码是使用numpy做数字运算,并且常常有很多的循环,那么使用Numba就是一个很好的选择。

下面是Numba适合和不适合应用场景的示例:

from numba import jit
import numpy as np

x = np.arange(100).reshape(10, 10)

@jit(nopython=True) # Set "nopython" mode for best performance, equivalent to @njit
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))

从上面的示例可以看出,Numba适合numpy中的循环操作、numpy函数以及broadcasting。

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不适合字典型变量和一些非numpy的函数,尤其是上面numba不能解析pandas,上面的函数内容在运行时也就无法编译。

关于nopython模式:

Numba中的@jit运算符能按照两种编译模式运行,nopython模式和object模式。例如上面的go_fast函数,nopython=true,将@jit设置为nopython模式。nopython编译模式的行为本质上是编译装饰函数,以便它完全运行而不需要Python解释器的参与。这是使用Numba jit装饰器的推荐和最佳实践方式,因为它可以带来最佳性能。

如果nopython模式下的编译失败,Numba可以使用对象模式进行编译,如果未设置nopython = True,则这是@jit装饰器的fall back模式(如上面的use_pandas示例中所示)。在这种模式下,Numba将识别它可以编译的循环,并将它们编译成在机器代码中运行的函数,并且它将运行解释器中的其余代码。为获得最佳性能,请避免使用此模式。

如何去衡量Numba的性能:

首先,numba在第一次执行的时候会执行函数编译为机器代码,这是需要耗时的,但是后面numba会将编译好的机器代码缓存起来以供后面的循环调用。

注意一个地方,如果编译时间很长,那么numba是支持将编译好的函数存到disk上的。

Numba是如何工作的:

Numba读取了@jit函数的python字节,并且分析优化代码,最后使用LLVM编译器生成函数的机器代码。

Numba中的decorators:

@njit @njit(nopython=true)的简称

 二、安装

安装完成以后,可以使用 numba-s 命令报告整个系统的信息。(是在命令行里面)

三、编译python代码,使用@jit

基本使用:

1、Lazy compilation

使用@jit的推荐方式为使用numba去决定如何去优化:

from numba import jit

@jit
def f(x, y):
    # A somewhat trivial example
    return x + y

在这种模式之下,编译会被推迟到第一次执行这个函数,numba回去推断输入的参数类型,然后据此做出优化。如果第一次调用的时候传入的是整数,而后面某次传入的是复数,会再次编译生成不同的机器代码。

2、Eager compilation

这种方式是在定义函数的时候确定使用什么样的数据类型。

from numba import jit, int32

@jit(int32(int32, int32))
def f(x, y):
    # A somewhat trivial example
    return x + y

这种做法是对编译器做出了fine-grained的控制。上面括号外面的int32指的是返回的数据类型,(int32,int32)指的是输入的参数类型。

调用和内联其他函数:

@jit
def square(x):
    return x ** 2

@jit
def hypot(x, y):
    return math.sqrt(square(x) + square(y))

注意上面hypot调用了square这个函数,@jit必须要添加在square这个函数上面,否则的话,会生成更慢的代码。

@jit可以使用的数据类型:

void: 空类型

int8,uint8 ...16...32...64等

intc, uintc 和 int, unsigned int是一样的

intp, uintp是pointer-sized integers (没有搞懂)

float32,float64

complex64,complex128

编译options:

1、nopython:

选择nopython模式或者是object模式

2、nogil

该项设置为true,一旦编译完成,就会释放GIL,这样的情况下就可以充分利用多核系统,但是需要注意多线程编程中需要注意的同步、一致性、竞争等情况。

3、cache

为了避免每次编译所耗费的时间,可以将函数编译完成的结果保存在一个file文件中。

4、parallel

自动并行化,注意需要和nopython=true一起使用

@jit(nopython=True, parallel=True)
def f(x, y):
    return x + y
Measure
Measure
Summary | 8 Annotations
其使用Numpy的arrays,functions和loops
2021/02/07 11:59
编译为机器代码即时执行
2021/02/07 11:59
numpy做数字运算,并且常常有很多的循环,那么使用Numba就是一个很好的选择
2021/02/07 11:59
Numba适合numpy中的循环操作、numpy函数以及broadcasting。
2021/02/07 11:59
将@jit设置为nopython模式。nopython编译模式的行为本质上是编译装饰函数,以便它完全运行而不需要Python解释器的参与。这是使用Numba jit装饰器的推荐和最佳实践方式,因为它可以带来最
2021/02/07 12:00
如果nopython模式下的编译失败
2021/02/07 12:00
对象模式进行编译
2021/02/07 12:00
将识别它可以编译的循环,并将它们编译成在机器代码中运行的函数,并且它将运行解释器中的其余代码
2021/02/07 12:01