numba用户手册
使用自动并行化@jit
-------------------------------------------------------------------------------------------------------------------------
2.1.numba会自动并行化代码:
具有target="parallel"选项Ufuncs和gufuncs 将在多个线程上运行.
该parallel=True选项@jit将尝试优化数组运算和并行运行它们.它还增加了prange()对显式并行化循环的支持.
您还可以自己在多个线程上手动运行计算,并使用该nogil=True选项(请参见释放GIL).
numba还可以使用其CUDA和HSA后端在GPU架构上实现并行执行.
-------------------------------------------------------------------------------------------------------------------------
2.2.说明:
1)仅适用于CPU.与vectorize()或guvectorize()机制相反,后者需要人工来创建并行内核.
2)数组表达式支持所有numba数组运算,numpy数组间,数组与标量间及ufuncs中通用算术函数.
3)当操作数具有匹配大小时支持多维数组.不支持在选定维度上进行归约
4)支持使用的reduce运算符functools在1D numpy数组上指定并行约简,但必须使用初始值参数
5)parallel=True时prange代替 range指定循环可并行化.要求确保循环除了支持的缩减以外没有交叉迭代依赖项.
6)利用并行硬件唯一要求是设置并行选项jit(),而无需修改函数.等效并行实现guvectorize()将需进行大范围的更改
7)循环体内只能用+=,-= ,*=,和/=.
-------------------------------------------------------------------------------------------------------------------------
# 实例1:
from numba import njit, prange
@njit(parallel=True) #并行循环
def prange_test(A):
s = 0
for i in prange(A.shape[0]): #无parallel=True,prange语句相当于range
s += A[i]
return s
-------------------------------------------------------------------------------------------------------------------------
# 实例2:
@njit(parallel=True) #二维数组上的乘积约简
def two_d_array_reduction_prod(n):
size = (13, 17)
result = 2 * np.ones(size, np.int_)
tmp = 2 * np.ones_like(result)
for i in prange(n):
result *= tmp
return result
-------------------------------------------------------------------------------------------------------------------------
# 实例3.1:
# 如切片或索引指定元素同时由多个并行线程写入,则在简化为数组的切片或元素时应格外小心.
# 编译器可能不会检测到这种情况,会出现竞争状况.
@njit(parallel=True)
def prange_wrong_result(x): #并行for循环竞争条件导致错误的返回值
n = x.shape[0]
y = np.zeros(4)
for i in prange(n): #从循环不同并行迭代中累积到同一个元素‘y’中,导致一个竞赛条件
y[:] += x[i]
return y
# 实例3.2:明确指定了累计元素:
@njit(parallel=True)
def prange_wrong_result(x):
n = x.shape[0]
y = np.zeros(4)
for i in prange(n): #从循环的不同并行迭代中累积到同一个元素‘y’中,导致一个竞赛条件
y[i % 4] += x[i]
return y
# 实例3.3:执行整个数组归约可以:
@njit(parallel=True)
def prange_ok_result_whole_arr(x):
n = x.shape[0]
y = np.zeros(4)
for i in prange(n):
y += x[i]
return y
# 实例3.4:就像在并行归约循环之外创建切片参考一样:
@njit(parallel=True)
def prange_ok_result_outer_slice(x):
n = x.shape[0]
y = np.zeros(4)
z = y[:]
for i in prange(n):
z += x[i]
return y
-------------------------------------------------------------------------------------------------------------------------
# 实例4:并行化Logistic回归:
@numba.jit(nopython=True, parallel=True)
def logistic_regression(Y, X, w, iterations):
for i in range(iterations):
w -= np.dot(((1.0 / (1.0 + np.exp(-Y * np.dot(X, w))) - 1.0) * Y), X)
return w
-------------------------------------------------------------------------------------------------------------------------