Numba 開發手冊(一)


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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM