官网:http://numba.pydata.org/numba-doc/0.12.2/index.html
用途:装饰器通过Numba的JIT编译器标记要优化的函数.各种调用模式会触发不同的编译选项和行为
1. Numba是什么?
Numba是一个库,可以在运行时将Python代码编译为本地机器指令,而不会强制大幅度的改变普通的Python代码(稍后再做说明)。翻译/魔术是使用LLVM编译器完成的,该编译器是相当活跃的开源社区开发的。
Numba最初是由Continuum Analytics内部开发,此公司也开发了著名的Anaconda,但现在它是开源的。核心应用领域是math-heavy(密集数学?重型数学?)和array-oriented(面向数组)的功能,它们在本地Python中相当缓慢。想象一下,在Python中编写一个模块,必须一个元素接着一个元素的循环遍历一个非常大的数组来执行一些计算,而不能使用向量操作来重写。这是很不好的主意,是吧?所以“通常”这类库函数是用C / C ++或Fortran编写的,编译后,在Python中作为外部库使用。Numba这类函数也可以写在普通的Python模块中,而且运行速度的差别正在逐渐缩小。
2.Numba的安装
pip install numba
conda install numba
3.简单例子
import time
import numba as nb
import numpy as np
@nb.jit
def sum_sq(a):
result=0
N=len(a)
for i in range(N):
result+=a[i]
return result
if __name__ == '__main__':
x=np.random.rand(10000000)
ord_stime=time.time()
sum_sq.py_func(x)
ord_etime=time.time()
ord_use=ord_etime-ord_stime
print("原始使用:{} s".format(ord_use))
nb_stime = time.time()
sum_sq(x)
nb_etime = time.time()
nb_use = nb_etime - nb_stime
print("nb使用:{} s".format(nb_use))
#原始使用:2.9910032749176025 s
#nb使用:0.19051742553710938 s
4.数据类型
print(nb.types.__all__)
'''
['int8', 'int16', 'int32', 'int64', 'uint8', 'uint16', 'uint32', 'uint64', 'intp', 'uintp', 'intc', 'uintc', 'boolean', 'float32', 'float64', 'complex64', 'complex128', 'bool_', 'byte', 'char', 'uchar', 'short', 'ushort', 'int_', 'uint', 'long_', 'ulong', 'longlong', 'ulonglong', 'float_', 'double', 'void', 'none', 'b1', 'i1', 'i2', 'i4', 'i8', 'u1', 'u2', 'u4', 'u8', 'f4', 'f8', 'c8', 'c16', 'optional', 'ffi_forced_object', 'ffi', 'deferred_type']
'''
'''
固定宽度整数:'int_','int8', 'int16', 'int32','int64','uint8','uint16','uint32','uint64'; 'short','ushort','int_','uint','long_','ulong','longlong', 'ulonglong',
整形指针: 'intp', 'uintp'
C整形数: 'intc', 'uintc'#等效于C int,unsigned int
浮点数: 'float32','float64''float_','double','long double' #单精度和双精度浮点数
复数: 'complex64','complex128' #单精度和双精度复数
'''
1.数组类型:通过索引任何数字类型来指定
#float32[:] 一维单精度数组;int8[:,:]8位整数二维数组
2.Numba装饰器:
@njit- 别名@jit(nopython=True)#引发错误
@vectorize- 产生NumPy ufunc(ufunc支持所有方法)
@guvectorize- 产生NumPy广义ufuncs
@stencil- 将函数声明为模板操作的内核
@jitclass- 针对jit的类
@cfunc- 声明一个用作本机回调的函数(从C / C ++等中调用)
@overload- 注册自己的函数实现以在nopython模式下使用,例如@overload(scipy.special.j0).
装饰器中其他选项:
parallel = True- 启用功能的 自动并行化.
fastmath = True- 为该功能启用快速行为.
ctypes / cffi / cython互操作性:
cffi- 在模式下支持CFFI函数的调用nopython
ctypes- 在模式下支持ctypes包装函数的调用nopython
Cython 导出的函数是可调用的.
参考:https://blog.csdn.net/tcy23456/article/details/103962948
5.例子
# 实例1.1:推断类型
@jit #支持所有类型(每次检查参数类型计算速度降低)编译将推迟到函数执行之前.
def f(x, y):return x + y
f(1j, 2) #根据输入类型来单独编译
--------------------------------------------------------------------------------------------------------------
# 实例1.2:给出函数类型
@jit("f8[:](f4,i4,i4)")
@jit(["int32(int32, int32)", "float32(float32, float32)"])
@jit(float64[:](float32,int32,nb.int_)) #返回1D数组
@jit("f8[:](f4,i4,i4)", nopython=True, nogil=True)
@jit("float64[:](float32,int32,int_)", nopython=True, nogil=True)
def fun_f(a, b, n):
res = np.empty(n, dtype=np.float64)
for i in range(n):
res[i] = i*a+b
return res
fun_f(11,22,2)
--------------------------------------------------------------------------------------------------------------
#实例1.3:list参数
@njit
def add_lst(lst,x):
for i,v in enumerate(lst):lst[i]+=x
return lst
nb_lst = nb.typed.List()
[ nb_lst.append(x) for x in [1,2,3]]
add_lst(nb_lst,100) #ListType[int64]([101, 102, 103])
--------------------------------------------------------------------------------------------------------------
#实例1.4:Numba编译函数可调用其他编译函数
@jit #其他函数必须被@jit装饰,否则Numba可产生慢得多的代码
def square(x):return x ** 2
@jit
def hypot(x, y):return math.sqrt(square(x) + square(y))
--------------------------------------------------------------------------------------------------------------
2.参数nogil #将代码优化为仅适用于本机类型和变量,释放全局解释器锁(GIL)
@jit(nogil=True) #警惕多线程编程的常见陷阱(一致性,同步,竞争条件等)
def f(x, y):
return x + y
--------------------------------------------------------------------------------------------------------------
3.参数cache #将函数编译结果写文件缓存,避免每次调用程序都编译
@jit(cache=True)
def f(x, y):
return x + y
--------------------------------------------------------------------------------------------------------------
4.参数parallel=True+nopython=True #为具有并行语义函数中操作启用自动并行化
@jit(nopython=True, parallel=True)
def f(x, y):
return x + y
————————————————
原文链接:https://blog.csdn.net/tcy23456/article/details/103962991
6.多线程
7.1说明:
1)并行执行通过parallelCPU 发生的即:
@jit(parallel=True). and @njit(parallel=True).
@vectorize(target='parallel' ) and @guvectorize(target='parallel' ).
2)如不用threading或multiprocessing ,则numba附带线程的默认设置会很好工作,无需采取进一步措施!
7.2.线程层:
1)tbb - Intel TBB支持的线程层(需要存在英特尔的TBB库conda install tbb)
2)omp -OpenMP支持的线程层(与linux1兼容移植性在PyPI上numba二进制轮子中禁用OpenMP线程层 )($ conda install intel-openmp)
3)workqueue -一个简单的内置工作共享任务计划程序(保证存在的唯一线程层)
7.3.设置线程层
通过环境变量 设置线程层 numba.config.THREADING_LAYER
编程方式设置线程层必须在逻辑上发生,后再针对并行目标进行任何基于numba的编译.
7.4.选择线程层
有两种方法,一种是通过选择在各种并行执行形式下安全的线程层,第二种是通过线程层名称(例如tbb)进行显式选择.
default 没有提供具体的安全保证,并且是默认设置.
safe 线程和线程都是安全的,这需要安装tbb软件包(Intel TBB库)
forksafe 提供一个fork安全库.
threadsafe 提供线程安全库.
------------------------------------------------------------------------------------------------------------------------------------------------------
7.5.实例:
from numba import config, njit, threading_layer
import numpy as np
config.THREADING_LAYER = 'threadsafe' # 在任何并行目标编译之前设置线程层
@njit(parallel=True)
def foo(a, b):
return a + b
x = np.arange(10.)
y = x.copy()
# 这将强制编译函数,选择一个线程层,然后并行执行
foo(x, y)
# 演示所选的线程层
print("Threading layer chosen: %s" % threading_layer()) # 查看所选的线程层
————————————————
原文链接:https://blog.csdn.net/tcy23456/article/details/103963092