1. 程式人生 > >Python的執行速度慢!這點是公認的,加上這操作快N倍!你信嗎?

Python的執行速度慢!這點是公認的,加上這操作快N倍!你信嗎?

Python的執行速度慢!這點是公認的,加上這操作快N倍!你信嗎?

 

開箱即用的Numba使用以下方法:

  • 作業系統:Windows(32位和64位),OSX和Linux(32位和64位)
  • 架構:x86,x86_64,ppc64le。 在armv7l,armv8l(aarch64)上進行實驗。
  • GPU:Nvidia CUDA。 AMD ROC的實驗。
  • CPython的
  • NumPy 1.10 - 最新

1.1.1。 我怎麼得到它?

Numba可作為 暢達 包為 蟒蛇Python釋出 :

$ conda install numba

Numba還有pip可供選擇:

$ pip install numba

Numba也可以 從原始碼編譯 ,雖然我們不建議首次使用Numba使用者。

Numba通常用作核心包,因此其依賴性保持在絕對最小值,但是,可以按如下方式安裝額外的包以提供其他功能:

進群:548377875  即可獲取小編精心整理的全套資料哦!還有大量的Pdf呢!

Python的執行速度慢!這點是公認的,加上這操作快N倍!你信嗎?

 

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
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))

對於看起來像這樣的程式碼,如果有的話,它將無法正常工作:

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不理解Pandas,因此Numba只是通過直譯器執行此程式碼,但增加了Numba內部開銷的成本!

1.1.3。 什麼是 nopython 模式?

Numba @jit 裝飾器從根本上以兩種編譯模式執行, nopython 模式和 object 模式。 在 go_fast 上面 的 例子中, nopython=True 在 @jit 裝飾器中 設定 ,這是指示Numba在 nopython 模式下 操作 。 nopython 編譯模式 的行為 本質上是編譯裝飾函式,以便它完全執行而不需要Python直譯器的參與。 這是使用Numba jit 裝飾器 的推薦和最佳實踐方式, 因為它可以帶來最佳效能。

如果編譯 nopython 模式失敗,Numba可以編譯使用 , 如果 沒有設定 ,這是 裝飾器的 後退模式 (如上 例所示)。 在這種模式下,Numba將識別它可以編譯的迴圈並將它們編譯成在機器程式碼中執行的函式,並且它將執行直譯器中的其餘程式碼。 為獲得最佳效能,請避免使用此模式 objectmode @jit nopython=True use_pandas

1.1.4。 如何衡量Numba的表現?

首先,回想一下,Numba必須為執行函式的機器程式碼版本之前給出的引數型別編譯函式,這需要時間。 但是,一旦編譯完成,Numba會為所呈現的特定型別的引數快取函式的機器程式碼版本。 如果再次使用相同的型別呼叫它,它可以重用快取的版本而不必再次編譯。

測量效能時,一個非常常見的錯誤是不考慮上述行為,並使用一個簡單的計時器來計算一次,該計時器包括在執行時編譯函式所花費的時間。

例如:

from numba import jit
import numpy as np
import time
x = np.arange(100).reshape(10, 10)
@jit(nopython=True)
def go_fast(a): # Function is compiled and runs in machine code
 trace = 0
 for i in range(a.shape[0]):
 trace += np.tanh(a[i, i])
 return a + trace
# DO NOT REPORT THIS... COMPILATION TIME IS INCLUDED IN THE EXECUTION TIME!
start = time.time()
go_fast(x)
end = time.time()
print("Elapsed (with compilation) = %s" % (end - start))
# NOW THE FUNCTION IS COMPILED, RE-TIME IT EXECUTING FROM CACHE
start = time.time()
go_fast(x)
end = time.time()
print("Elapsed (after compilation) = %s" % (end - start))

這,例如列印:

Elapsed (with compilation) = 0.33030009269714355
Elapsed (after compilation) = 6.67572021484375e-06

衡量Numba JIT對您的程式碼的影響的一個好方法是使用 timeit 模組函式 來執行時間 ,這些函式測量多次執行迭代,因此可以在第一次執行時適應編譯時間。

作為旁註,如果編譯時間成為問題,Numba JIT支援 編譯函式 的磁碟快取 ,並且還具有 Ahead-Of-Time 編譯模式。

1.1.5。 它有多快?

假設Numba可以在 nopython 模式下執行,或者至少編譯一些迴圈,它將針對您的特定CPU進行編譯。 加速因應用而異,但可以是一到兩個數量級。 Numba有一個 效能指南 ,涵蓋了獲得額外效能的常用選項。

1.1.6。 Numba如何運作?

Numba讀取裝飾函式的Python位元組碼,並將其與有關函式輸入引數型別的資訊相結合。 它分析並優化您的程式碼,最後使用LLVM編譯器庫生成函式的機器程式碼版本,根據您的CPU功能量身定製。 每次呼叫函式時都會使用此編譯版本。

1.1.7。 其他感興趣的東西:

Numba有相當多的裝飾,我們看到 @jit 和 @njit ,但也有:

  • @vectorize - 生成NumPy ufunc ( ufunc 支援 所有 方法)。 檔案在這裡 。
  • @guvectorize - 產生NumPy廣義 ufunc s。 檔案在這裡 。
  • @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匯出的函式 是可呼叫的 。

1.1.7.1。 GPU目標:

Numba可以針對 Nvidia CUDA 和(實驗性) AMD ROC GPU。 您可以使用純Python編寫核心,讓Numba處理計算和資料移動(或明確地執行此操作)。 單擊關於 CUDA 或 ROC的 Numba文件 。

示例:接下來我們寫一段簡單的程式碼,來計算一下執行時間:

示例1:不使用numba的:

import time
def num():
 arr = []
 for i in range(10000000):
 arr.append(i)
stime = time.time()
num()
etime = time.time() - stime
# print(arr)
print('用時:{}秒'.format(etime))

示例輸出時間:

用時:1.4500024318695068秒

示例2:使用numba @jit

import time
from numba import jit
@jit
def num():
 arr = []
 for i in range(10000000):
 arr.append(i)
stime = time.time()
num()
etime = time.time() - stime
# print(arr)
print('用時:{}秒'.format(etime))

示例輸出:

用時:0.5530002117156982秒

結論:

上述兩個示例程式碼,一個使用了numba,另一個沒有使用numba;可以看出使用numba @jit裝飾後,時間明顯快了很多倍。

這只是一個簡單示例;對於複雜計算提高速度更明顯。

Python的執行速度慢!這點是公認的,加上這操作快N倍!你信嗎?