使用 numba.jit 加速代码

Accelerating code using numba.jit

我正在尝试使用 numba.jit 加速 python 程序。

我的程序的一个函数将 float 数组和一个标量相乘,标量始终是整数。

import numpy
myarray = numpy.array([0.2,0.26,0.45,0.78],dtype=float)

def multiply(array, scalar):
    newarray = array * scalar
    return newarray

newarray = multiply(myarray,5)

当我 numba.jit() 我的函数具有以下签名时,函数运行速度慢了一个数量级:

fastmultiply = numba.jit("f4[:](f4[:],int8)")(multiply)

这是因为我声明了错误的数据类型:f4[:]int8?

或者我的函数编码方式不允许使用 numba.jit() 进行加速?

工作量经济 v/s 生成的 jit 代码重用量

JIT 在某些情况下可以提供帮助,其中大量的重用证明了即时编译的成本。

代码的第一个 运行 因此需要更长的时间,因为 .jit() 编译器处理源代码。

注意工作的经济性 - 对于 "short" 代码,这可能比最终的 jit 编译产品花费几个数量级的时间,因此调整这样的初始只有在有数百万个重复使用案例时,机会成本惩罚才可能变得合理。

对于很多 "more computationally intensive" 代码,通常是非平凡的卷积、迭代再处理方法等,即使对于单个案例,jit 编译的成本也可能变得合理。


@numba.jit() signatures

好吧,这是一个单独的主题,错误的类型可能会挂起您的处理。

显式 .jit() 签名或 .autojit()? 这就是哈姆雷特的困境。

好吧,这取决于您的喜好。 定量证据 应收集关于两种方法的初始调用/重复使用调用的持续时间,并根据重复使用调用的预期数量(成本/收益不平等)来决定。

#numba.jit( 'f4[:](i4,f4[:])' )                              # .float32 # [DONE] PERF.ToDo.MS:
#numba.jit( 'f4[:](i8,f8[:])' )                   # .float32 # .float64 # [DONE] PERF.ToDo.MS:
@jit(       'f8[:](i8,f8[:])' )                              # .float64 # [DONE] PERF.ToDo.MS:
def numba_EMA_fromPrice( N_period, aPriceVECTOR ):                      # TEST:         perf (non)-jit Stopwatch.start();;Stopwatch.stop()
    ...

# @numba.jit [usec]----------------------------------------- PERFORMANCE PROFILING
aClk.start();numba_EMA_fromPrice( 8, price_H4_CLOSE );aClk.stop()
Out[112]: 160814L                         # 1. JIT-compile
Out[113]:    331L                         # re-use 0.3xy[ms] v/s 11.5[ms] CPython
Out[114]:    311L
Out[115]:    324L
#
# @numba.guvectorize()
# @numba.jit( nogil = True )              # JIT w/o GIL-lock w/ multi-CORE ** WARNING: ThreadSafe / DataCoherency measures **
aClk.start();numba_EMA_fromPrice( 8, price_H4_CLOSE );aClk.stop()
Out[126]: 149929L                         # 1. JIT-compile
Out[127]:    284L                         # re-use 0.28[ms] v/s 11.5[ms] CPython
Out[128]:    256L

autojit() 个签名的额外成本,需要 analyzing/adapting,可能会扭曲成本/收益不平等的边缘。

.jit() 显式签名的维护 可能会令人头疼。

小心:

np.float不是f4

|>>> np.arange( 2, dtype = float ).dtype
dtype('float64')

下一个,有些情况(np.nan_to_num()就是其中之一),可能会收到 "静默" 将 dtype 向上转换为 np.float64,这可能会导致令人头疼的寻找 dtypenumba.jit() 显式冲突的地方签名。