網址: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