有人可以幫我為這個例子創建一個 cython 代碼嗎?
我創建這個示例是因為我想創建一個更快的版本,作為我正在考慮的解決方案賽通和/或麻木的,但如果有其他方式,請隨時提出。
該代碼旨在從前一個串列(list1 隨機生成)開始生成一個 3d 串列(稱為 list2)。
它使用兩個轉換函式(transform 和 trasform1):一個只執行一些亂數學運算(transform),另一個使用 list1 生成要插入到 list2 中的最終值。
我跟蹤時間個人資料
代碼如下:
import math
from random import seed
from random import random
global i_elements
global j_elements
global k_elements
i_elements,j_elements,k_elements =11,11,11
global list1
global list2
seed(1)
list1 = [[[random() for k in range(i_elements)] for j in range(j_elements)] for i in range(k_elements)]
list2 = [[[0 for k in range(i_elements)] for j in range(j_elements)] for i in range(k_elements)]
def transform(x, y, z):
'''
no-sense function performing some math
'''
a = 0
b = 0
sol = 0
if x > y:
a = math.sqrt(x ** 2) math.atan(y ** 2 1)
else:
b = math.sqrt(z ** 2) math.atan(y ** 2 1)
if x > z:
sol = math.sqrt(a*b)
else:
sol = math.sqrt(b**2)
return sol
def transform2(a, b, c):
'''
transformation dependent on element in list1
'''
global list1, i_elements,j_elements,k_elements
sol = 0
for i in range(i_elements):
for j in range(j_elements):
for k in range(k_elements):
temp = transform(i, j, k)
if list1[i][j][k] > temp:
sol = temp*list1[i][j][k]*(a 1)**2
else:
sol = temp list1[i][j][k]**(b*c 1)
return sol
def save_list():
'''
function to save my 3d list after the transform2
'''
global list2,i_elements, j_elements, k_elements
for i in range(i_elements):
for j in range(j_elements):
for k in range(k_elements):
list2[i][j][k] = transform2(i,j,k)
return list2
def main():
save_list()
print('finish')
if __name__ == "__main__":
import cProfile
cProfile.run('main()')
輸出是:
finish
7087581 function calls in 2.628 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 2.628 2.628 <string>:1(<module>)
1771561 1.453 0.000 1.932 0.000 code_to_speed_up.py:17(transform)
1331 0.696 0.001 2.628 0.002 code_to_speed_up.py:37(transform2)
1 0.001 0.001 2.628 2.628 code_to_speed_up.py:56(save_list)
1 0.000 0.000 2.628 2.628 code_to_speed_up.py:68(main)
1 0.000 0.000 2.628 2.628 {built-in method builtins.exec}
1 0.000 0.000 0.000 0.000 {built-in method builtins.print}
1771561 0.178 0.000 0.178 0.000 {built-in method math.atan}
3543122 0.301 0.000 0.301 0.000 {built-in method math.sqrt}
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
uj5u.com熱心網友回復:
Numpy 可用于解決此問題,但transform2很難有效地矢量化。然而,Cython 和 Numba 可以有效地做到這一點(Numba 有點像 Cython,但它是一個即時編譯器,在這里使用起來更簡單)。
單獨使用 Cython 或 Numba 是不夠的,因為無法有效地計算串列(由于參考計數、GIL、導致額外間接的低效內部表示等)。
請注意,使用全域變數不是一個好主意。它通常速度較慢,并且使您的代碼更難優化和理解(這被視為一種糟糕的軟體工程實踐,尤其是在修改全域變數時,因為它會導致隱藏的依賴關系,或者說是一種遠距離的詭異動作)。
這是一個使用 Numpy Numba 的(幾乎沒有經過測驗的)示例:
import math
import numpy as np
import numba as nb
i_elements,j_elements,k_elements = 11,11,11
np.random.seed(1)
arr1 = np.random.rand(i_elements, j_elements, k_elements)
arr2 = np.zeros((i_elements, j_elements, k_elements))
@nb.njit
def transform(x, y, z):
'''
no-sense function performing some math
'''
a = 0
b = 0
sol = 0
if x > y:
a = math.sqrt(x ** 2) math.atan(y ** 2 1)
else:
b = math.sqrt(z ** 2) math.atan(y ** 2 1)
if x > z:
sol = math.sqrt(a*b)
else:
sol = math.sqrt(b**2)
return sol
@nb.njit
def transform2(arr1, a, b, c):
'''
transformation dependent on element in arr1
'''
sol = 0
for i in range(arr1.shape[0]):
for j in range(arr1.shape[1]):
for k in range(arr1.shape[2]):
temp = transform(i, j, k)
if arr1[i,j,k] > temp:
sol = temp * arr1[i,j,k] * (a 1)**2
else:
sol = temp arr1[i,j,k]**(b*c 1)
return sol
# Giving a signature to Numba helps him to compile the function eagerly
# Read the doc for more information about this.
@nb.njit('(float64[:,:,::1],float64[:,:,::1])')
def save_list(arr1, arr2):
'''
function to save my 3d list after the transform2
'''
for i in range(arr2.shape[0]):
for j in range(arr2.shape[1]):
for k in range(arr2.shape[2]):
arr2[i,j,k] = transform2(arr1, i,j,k)
return arr2
def main():
global arr1
global arr2
save_list(arr1, arr2)
print('finish')
if __name__ == "__main__":
import cProfile
cProfile.run('main()')
請注意,np.random.rand盡管種子設定為相同的值,但可能會產生不同的結果,因為 Numpy 肯定使用不同的亂數生成器實作。
如果你真的想使用 Cython 而不是 Numba,那么你需要使用 Numpy 記憶體視圖。有關更多資訊,請閱讀 Cython 檔案的Cython for NumPy 用戶教程。
在我的機器上快 500 倍以上。
請注意,returninsave_list不是很有用,因為它是傳入引數(對于全域變數也不是更有用)。另請注意,sol已分配,transform2這意味著只有最后一次迭代很重要(編譯器可以優化它)。但它非常可疑:它看起來像一個錯誤,您當然想要執行歸約(例如 =),特別是因為初始分配為 0。請檢查結果是否正確。
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/480782.html
