Numba:加速python代码

 通常我们加速python代码是考虑把.py文件编译成.c文件,然后把.c文件编译成.so或.pyd文件,可以参考另一章博文:

Cython为py程序加密&提高性能_cythonize_Rnan-prince的博客-CSDN博客

现在我们考虑一种不用将py文件编译成.c文件的方法:numba,其实原理差不多,只是用户不感知。

Numba简介

Numba是一款可以将python函数编译为机器代码的JIT编译器,经过Numba编译的python代码(仅限数组运算),其运行速度可以接近C或FORTRAN语言。普通python语言靠Cython编译的,但是Numba使用Jit编译器可以直接将一个函数转化为机器码。

User Manual — Numba 0.50.1 documentationicon-default.png?t=N7T8http://numba.pydata.org/numba-doc/latest/user/index.htmlJIT的全称是 Just-in-time,在 numba 里面则特指 Just-in-time compilation(即时编译)。

编译方式有:

  • 动态编译(dynamic compilation):指的是“在运行时进行编译”;与之相对的是事前编译(ahead-of-time compilation,简称AOT),也叫静态编译(static compilation)。
  • JIT编译(just-in-time compilation)狭义来说是当某段代码即将第一次被执行时进行编译,因而叫“即时编译”。JIT编译是动态编译的一种特例。JIT编译一词后来被泛化,时常与动态编译等价;但要注意广义与狭义的JIT编译所指的区别。
  • 自适应动态编译(adaptive dynamic compilation)也是一种动态编译,但它通常执行的时机比JIT编译迟,先让程序“以某种方式”先运行起来,收集一些信息之后再做动态编译。这样的编译可以更加优化。

Numba 的最基础应用就是加速 Python 中的循环操作。

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

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

jit装饰器

numba加速,针对数字运算,所以输入输出为数组格式

jit和njit的使用,要不要加(),括号有没有一样不一样

@jit() 里面可以增加参数,不添加参数设置时和jit一样

import jit
@numba.jit
def func(x,y):
    s = 1 
    for i in range(x, y):
        c *= i
    return c

上面这段代码是numba.jit的简单应用,在函数第一次执行的时候,numba推断出参数类型,然后基于这个信息生产优化后的代码。

指定签名

import numba 
@numba.jit(int32(int32, int32))
def func(x,y):
    s = 1 
    for i in range(x, y):
        c *= i
    return c

@numba.jit括号内的是指定签名,编译器将控制类型选择,并不允许其他类型的参数输入,这会带来速度上的优势。

常用的数据类型有:

  • int8, uint8, int16, uint16, int32, uint32, int64,uint64,各种长度整数。图像处理中unit8很常用。
  • float32 ,float64, 单精度浮点数,双精度浮点数
  • complex64 ,complex128, 单精度复数,双精度复数
  • void, 对应python中返回Nothing。
  • intc and uintc 等效于C中的 int 和uint
  • 各种数组类型,如float32[:]表示一维单精度浮点数组,uint8[:,:] 表示二维无符号8位整数数组(常用于图像数组)
  • 元组, 如nb.types.UniTuple(nb.float32, 3) 表示3个元素的元组,元素的类型是float32

重要参数 

编译模式(nopython模式和object模式)

nopython和object是numba的两种编译模式,前者编译的代码更快,但是可能会因为某些限制但是退化为object, 通过nopython=True可以阻止退化并抛出异常。

@njit() 是jit(nopython=True)的默认,@numba.njit与@numba.jit(nopython=True)等价。里面也可以增加设置,比如parallel=True,和prange的使用 只能对数字运算进行加速,建议使用njit,使用起来更加灵活一些

import jit
@numba.njit
def func(x,y):
    s = 1 
    for i in range(x, y):
        c *= i
    return c

nogil

当Numba不需要保持全局线程锁GIL时,可以设定nogil=True,当进入这类编译好的函数时,Numba将会释放全局线程锁。这样可以利用多核系统,但不能使用的函数是在object模式下编译。

@numba.jit(nogil=True)
def func(x,y):
    s = 1 
    for i in range(x, y):
        c *= i
    return c

 cache

想要避免你调用python程序的编译时间,可以通过cache=True来指定numba保存函数编译结果到一个基于文件的缓存中。

@numba.jit(cache=True)
def func(x,y):
    s = 1 
    for i in range(x, y):
        c *= i
    return c

parallel

parallel=True将函数中的操作自动并行化,必须要和nopython=True配合起来一起使用。在定义函数内部,有可并行且不会每次并行之间不会相互影响时使用。编译器将编译一个版本,并行运行多个原生的线程(没有GIL)。简单的for循环的话开启的效果就会比较明显。

@numba.jit(nopython=True, parallel=True)
def func(x,y):
    s = 1 
    for i in numba.prange(x, y):
        c *= i
    return c

boundchecks

什么时候应该 boundchecks 关闭

boundscheck: bool Set to True to enable bounds checking for array indices. Out of bounds accesses will raise IndexError. The default is to not do bounds checking. If bounds checking is disabled, out of bounds accesses can produce garbage results or segfaults. However, enabling bounds checking will slow down typical functions, so it is recommended to only use this flag for debugging. You can also set the NUMBA_BOUNDSCHECK environment variable to 0 or 1 to globally override this flag.

检查数组索引是否不对劲,但是费时间,在保证对的情况下可以设置为False

@numba.njit(boundcheck=False)
def func(x,y):
    s = 1 
    for i in range(x, y):
        c *= i
    return c

常见错误

1、Numba函数参数类型不匹配定义ListType[数组(float64,2d,C)]错误

类型在Numba官方网站上也找不到。让一个基于numba.typeof()返回的解析器函数能够创建装饰器的字符串也是非常有帮助的。注意:运行一定要将@njit(int32(int32))注释掉,否则报错

import numba
from numba import njit, int32


# @njit(int32(int32))
def func(a):
    print(numba.typeof(a))
    return a


func(3)
print(func.inspect_types())

 还有一个超级有用的行来获取numba函数的类型签名:func.inspect_types()

2、RuntimeError: cannot cache function 'square': no locator available for file · Issue #4908 ·

https://github.com/numba/numba/issues/4908icon-default.png?t=N7T8https://github.com/numba/numba/issues/4908

为什么python这么慢?numba解决了什么问题? 

这个大神讲的非常好:

为什么python这么慢?numba解决了什么问题? - 知乎


参考:

【深度好文】Python加速库Numba简介

python numba教程_Numba 开发手册(一)_不设目标的博客-CSDN博客

Numba函数参数类型不匹配定义ListType[数组(float64,2d,C)]错误-腾讯云开发者社区-腾讯云

利用numba給Python代码加速 [1]-腾讯云开发者社区-腾讯云

Numba CPU 并行 - 知乎

你可能感兴趣的:(python,python,开发语言)