精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

如何讓Python像Julia一樣快地運行

開發 后端
在我給出答案之前,我想說我絕不會試圖貶低 Julia。在進一步開發和改進后,Julia 無疑是一種值得關注的語言。我只是想分析 Python方面的事情。實際上,我正在以此為借口來探索各種可用于讓代碼更快運行的 Python 工具。

Julia 與 Python 的比較

我是否應丟棄 Python 和其他語言,使用 Julia 執行技術計算?在看到 http://julialang.org/ 上的基準測試后,人們一定會這么想。Python和其他高級語言在速度上遠遠有些落后。但是,我想到的***個問題有所不同:Julia 團隊能否以最適合 Python 的方式編寫 Python 基準測試?

我對這種跨語言比較的觀點是,應該根據要執行的任務來定義基準測試,然后由語言專家編寫執行這些任務的***代碼。如果代碼全由一個語言團隊編寫,則存在其他語言未得到***使用的風險。

Julia 團隊有一件事做得對,那就是他們將他們使用的代碼發布到了 github 上。具體地講,Python 代碼可在此處找到。

***眼看到該代碼,就可以證實我所害怕的偏見。該代碼是以 C 風格編寫的,在數組和列表上大量使用了循環。這不是使用 Python 的***方式。

我不會責怪 Julia 團隊,因為我很內疚自己也有同樣的偏見。但我受到了殘酷的教訓:付出任何代價都要避免數組或列表上的循環,因為它們確實會拖慢 Python中的速度,請參閱《Python 不是 C》。

考慮到對 C 風格的這種偏見,一個有趣的問題(至少對我而言)是,我們能否改進這些基準測試,更好地使用 Python 及其工具?

在我給出答案之前,我想說我絕不會試圖貶低 Julia。在進一步開發和改進后,Julia 無疑是一種值得關注的語言。我只是想分析 Python方面的事情。實際上,我正在以此為借口來探索各種可用于讓代碼更快運行的 Python 工具。

在下面的內容中,我使用 Docker 鏡像在 Jupyter Notebook 中使用 Python 3.4.3,其中已安裝了所有的 Python 科學工具組合。我還會通過Windows 機器上的 Python 2.7.10,使用 Anaconda 來運行代碼。計時是對 Python 3.4.3 執行的。包含下面的所有基準測試的完整代碼的 Notebook 可在此處(https://www.ibm.com/developerworks/community/blogs/jfp/resource/julia_python.zip)找到。

鑒于各種社交媒體上的評論,我添加了這樣一句話:我沒有在這里使用 Python 的替代性實現。我沒有編寫任何 C代碼:如果您不信,可試試尋找分號。本文中使用的所有工具都是 Anaconda 或其他發行版中提供的標準的 Cython 實現。下面的所有代碼都在單個 Notebook中運行。

我嘗試過使用來自 github 的 Julia 微性能文件,但不能使用 Julia 0.4.2 原封不動地運行它。我必須編輯它并將 @timeit 替換為@time,它才能運行。在對它們計時之前,我還必須添加對計時函數的調用,否則編譯時間也將包含在內。我使用的文件位于此處。我在用于運行 Python 的同一個機器上使用 Julia 命令行接口運行它。

計時代碼

Julia 團隊使用的***項基準測試是 Fibonacci 函數的一段簡單編碼。

  1. def fib(n): 
  2.  
  3.    if n<2: 
  4.  
  5.        return n 
  6.  
  7.    return fib(n-1)+fib(n-2) 

 

此函數的值隨 n 的增加而快速增加,例如:

  1. fib(100) = 354224848179261915075 

可以注意到,Python 任意精度 (arbitrary precision) 很方便。在 C 等語言中編寫相同的函數需要花一些編碼工作來避免整數溢出。在 Julia中,需要使用 BigInt 類型。

所有 Julia 基準測試都與運行時間有關。這是 Julia 中使用和不使用 BigInt 的計時:

  1. 0.000080 seconds (149 allocations:10.167 KB) 
  2.  
  3. 0.012717 seconds (262.69 k allocations:4.342 MB) 

 

在 Python Notebook 中獲得運行時間的一種方式是使用神奇的 %timeit。例如,在一個新單元中鍵入:

  1. %timeit fib(20) 

執行它會獲得輸出:

  1. 100 loops, best of 3:3.33 ms per loop 

這意味著計時器執行了以下操作:

  1. 運行 fib(20) 100 次,存儲總運行時間
  2. 運行 fib(20) 100 次,存儲總運行時間
  3. 運行 fib(20) 100 次,存儲總運行時間
  4. 從 3 次運行中獲取最小的運行時間,將它除以 100,然后輸出結果,該結果就是 fib(20) 的***運行時間

這些循環的大小(100 次和 3 次)會由計時器自動調整。可能會根據被計時的代碼的運行速度來更改循環大小。

Python 計時與使用了 BigInt 時的 Julia 計時相比出色得多:3 毫秒與 12 毫秒。在使用任意精度時,Python 的速度是 Julia 的 4倍。

但是,Python 比 Julia 默認的 64 位整數要慢。我們看看如何在 Python 中強制使用 64 位整數。

使用 Cython 編譯

一種編譯方式是使用 Cython 編譯器。這個編譯器是使用 Python

編寫的。它可以通過以下命令安裝:

  1. pip install Cython 

如果使用 Anaconda,安裝會有所不同。因為安裝有點復雜,所以我編寫了一篇相關的博客文章:將 Cython For Anaconda 安裝在 Windows 上

安裝后,我們使用神奇的 %load_ext 將 Cython 加載到 Notebook 中:

  1. %load_ext Cython 

然后就可以在我們的 Notebook 中編譯代碼。我們只需要將想要編譯的代碼放在一個單元中,包括所需的導入語句,使用神奇的 %%cython 啟動該單元:

  1. %%cython 
  2.  
  3.    
  4.  
  5. def fib_cython(n): 
  6.  
  7.     if n<2: 
  8.  
  9.         return n 
  10.  
  11.     return fib_cython(n-1)+fib_cython(n-2) 

 

執行該單元會無縫地編譯這段代碼。我們為該函數使用一個稍微不同的名稱,以反映出它是使用 Cython編譯的。當然,一般不需要這么做。我們可以將之前的函數替換為相同名稱的已編譯函數。

對它計時會得到:

  1. 1000 loops, best of 3:1.22 ms per loop 

哇,幾乎比最初的 Python 代碼快 3 倍!我們現在比使用 BigInt 的 Julia 快 100 倍。

我們還可以嘗試靜態類型。使用關鍵字 cpdef 而不是 def 來聲明該函數。它使我們能夠使用相應的 C 類型來鍵入函數的參數。我們的代碼變成了:

  1. %%cython 
  2.  
  3.   
  4.  
  5. cpdef long fib_cython_type(long n): 
  6.  
  7.    if n<2: 
  8.  
  9.      return n 
  10.  
  11.    return fib_cython_type(n-1)+fib_cython_type(n-2) 

 

執行該單元后,對它計時會得到:

  1. 10000 loops, best of 3:36 µs per loop 

太棒了,我們現在只花費了 36 微秒,比最初的基準測試快約 100 倍!這與 Julia 所花的 80 毫秒相比更出色。

有人可能會說,靜態類型違背了 Python的用途。一般來講,我比較同意這種說法,我們稍后將查看一種在不犧牲性能的情況下避免這種情形的方法。但我并不認為這是一個問題。Fibonacci函數必須使用整數來調用。我們在靜態類型中失去的是 Python 所提供的任意精度。對于 Fibonacci,使用 C 類型 long

會限制輸入參數的大小,因為太大的參數會導致整數溢出。

請注意,Julia 計算也是使用 64 位整數執行的,因此將我們的靜態類型版本與 Julia 的對比是公平的。

緩存計算

我們在保留 Python 任意精度的情況下能做得更好。fib 函數重復執行同一種計算許多次。例如,fib(20) 將調用 fib(19) 和fib(18)。fib(19) 將調用 fib(18) 和 fib(17)。結果 fib(18) 被調用了兩次。簡單分析表明,fib(17) 將被調用 3 次,fib(16) 將被調用 5 次,等等。

在 Python 3 中,我們可以使用 functools 標準庫來避免這些重復的計算。

  1. from functools import lru_cache as cache 
  2.  
  3. @cache(maxsize=None) 
  4.  
  5. def fib_cache(n): 
  6.  
  7.     if n<2: 
  8.  
  9.         return n 
  10.  
  11.     return fib_cache(n-1)+fib_cache(n-2) 

 

對此函數計時會得到:

  1. 1000000 loops, best of 3:910 ns per loop 

速度又增加了 40 倍,比最初的 Python 代碼快約 3,600 倍!考慮到我們僅向遞歸函數添加了一條注釋,此結果非常令人難忘。

Python 2.7 中沒有提供這種自動緩存。我們需要顯式地轉換代碼,才能避免這種情況下的重復計算。

  1. def fib_seq(n): 
  2.  
  3.    if n < 2: 
  4.  
  5.      return n 
  6.  
  7.    a,b = 1,0 
  8.  
  9.    for i in range(n-1): 
  10.  
  11.      a,b = a+b,a 
  12.  
  13.    return a 

 

請注意,此代碼使用了 Python 同時分配兩個局部變量的能力。對它計時會得到:

  1. 1000000 loops, best of 3:1.77 µs per loop 

我們又快了 20 倍!讓我們在使用和不使用靜態類型的情況下編譯我們的函數。請注意,我們使用了 cdef 關鍵字來鍵入局部變量。

  1. %%cython 
  2.  
  3.   
  4.  
  5. def fib_seq_cython(n): 
  6.  
  7.    if n < 2: 
  8.  
  9.         return n 
  10.  
  11.     a,b = 1,0 
  12.  
  13.     for i in range(n-1): 
  14.  
  15.         a,b = a+b,a 
  16.  
  17.     return a 
  18.  
  19. cpdef long fib_seq_cython_type(long n): 
  20.  
  21.     if n < 2: 
  22.  
  23.         return n 
  24.  
  25.     cdef long a,b 
  26.  
  27.     a,b = 1,0 
  28.  
  29.     for i in range(n-1): 
  30.  
  31.         a,b = a+b,b 
  32.  
  33.     return a 

 

我們可在一個單元中對兩個版本計時:

  1. %timeit fib_seq_cython(20) 
  2.  
  3. %timeit fib_seq_cython_type(20) 

 

結果為:

  1. 1000000 loops, best of 3:953 ns per loop 
  2.  
  3. 10000000 loops, best of 3:51.9 ns per loop 

 

靜態類型代碼現在花費的時間為 51.9 納秒,比最初的基準測試快約 60,000(六萬)倍。

如果我們想計算任意輸入的 Fibonacci 數,我們應堅持使用無類型版本,該版本的運行速度快 3,500 倍。還不錯,對吧?

使用 Numba 編譯

讓我們使用另一個名為 Numba 的工具。它是針對部分 Python 版本的一個即時

(jit) 編譯器。它不是對所有 Python 版本都適用,但在適用的情況下,它會帶來奇跡。

安裝它可能很麻煩。推薦使用像 Anaconda 這樣的 Python 發行版或一個已安裝了 Numba 的 Docker 鏡像。完成安裝后,我們導入它的 jit 編譯器:

  1. from numba import jit 

它的使用非常簡單。我們僅需要向想要編譯的函數添加一點修飾。我們的代碼變成了:

  1. @jit 
  2.  
  3. def fib_seq_numba(n): 
  4.  
  5.     if n < 2: 
  6.  
  7.         return n 
  8.  
  9.     (a,b) = (1,0) 
  10.  
  11.     for i in range(n-1): 
  12.  
  13.         (a,b) = (a+b,a) 
  14.  
  15.     return a 

 

對它計時會得到:

  1. 1000000 loops, best of 3:225 ns per loop 

比無類型的 Cython 代碼更快,比最初的 Python 代碼快約 16,000 倍!

使用 Numpy

我們現在來看看第二項基準測試。它是快速排序算法的實現。Julia 團隊使用了以下 Python 代碼:

  1. def qsort_kernel(a, lo, hi): 
  2.  
  3.     i = lo 
  4.  
  5.     j = hi 
  6.  
  7.     while i < hi: 
  8.  
  9.         pivot = a[(lo+hi) // 2] 
  10.  
  11.         while i <= j: 
  12.  
  13.             while a[i] < pivot: 
  14.  
  15.                 i += 1 
  16.  
  17.             while a[j] > pivot: 
  18.  
  19.                 j -= 1 
  20.  
  21.             if i <= j: 
  22.  
  23.                 a[i], a[j] = a[j], a[i] 
  24.  
  25.                 i += 1 
  26.  
  27.                 j -= 1 
  28.  
  29.         if lo < j: 
  30.  
  31.             qsort_kernel(a, lo, j) 
  32.  
  33.         lo = i 
  34.  
  35.         j = hi 
  36.  
  37.     return a 

 

我將他們的基準測試代碼包裝在一個函數中:

  1. import random 
  2.  
  3. def benchmark_qsort(): 
  4.  
  5.     lst = [ random.random() for i in range(1,5000) ] 
  6.  
  7.     qsort_kernel(lst, 0, len(lst)-1) 

 

對它計時會得到:

  1. 100 loops, best of 3:18.3 ms per loop 

上述代碼與 C 代碼非常相似。Cython 應該能很好地處理它。除了使用 Cython 和靜態類型之外,讓我們使用 Numpy

數組代替列表。在數組大小較大時,比如數千個或更多元素,Numpy 數組確實比Python 列表更快。

安裝 Numpy 可能會花一些時間,推薦使用 Anaconda 或一個已安裝了 Python 科學工具組合的 Docker 鏡像。

在使用 Cython 時,需要將 Numpy 導入到應用了 Cython 的單元中。在使用 C 類型時,還必須使用 cimport 將它作為 C 模塊導入。Numpy數組使用一種表示數組元素類型和數組維數(一維、二維等)的特殊語法來聲明。

  1. %%cython 
  2.  
  3.   
  4.  
  5. import numpy as np 
  6.  
  7. cimport numpy as np 
  8.  
  9. cpdef np.ndarray[double, ndim=1] \ 
  10.  
  11. qsort_kernel_cython_numpy_type(np.ndarray[double, ndim=1] a, \ 
  12.  
  13. long lo, \ 
  14.  
  15. long hi): 
  16.  
  17. cdef: 
  18.  
  19. long i, j 
  20.  
  21. double pivot 
  22.  
  23. i = lo 
  24.  
  25. j = hi 
  26.  
  27.    while i < hi: 
  28.  
  29.      pivot = a[(lo+hi) // 2] 
  30.  
  31.      while i <= j: 
  32.  
  33.        while a[i] < pivot: 
  34.  
  35.          i += 1 
  36.  
  37.        while a[j] > pivot: 
  38.  
  39.          j -= 1 
  40.  
  41.        if i <= j: 
  42.  
  43.          a[i], a[j] = a[j], a[i] 
  44.  
  45.          i += 1 
  46.  
  47.          j -= 1 
  48.  
  49.      if lo < j: 
  50.  
  51.        qsort_kernel_cython_numpy_type(a, lo, j) 
  52.  
  53.      lo = i 
  54.  
  55.      j = hi 
  56.  
  57.    return a 
  58.  
  59.   
  60.  
  61. cpdef benchmark_qsort_numpy_cython(): 
  62.  
  63.   lst = np.random.rand(5000) 
  64.  
  65.   qsort_kernel_cython_numpy_type(lst, 0, len(lst)-1) 

 

對 benchmark_qsort_numpy_cython() 函數計時會得到:

  1. 1000 loops, best of 3:1.32 ms per loop 

我們比最初的基準測試快了約 15 倍,但這仍然不是使用 Python 的***方法。***方法是使用 Numpy 內置的 sort()函數。它的默認行為是使用快速排序算法。對此代碼計時:

  1. def benchmark_sort_numpy(): 
  2.  
  3. lst = np.random.rand(5000) 
  4.  
  5. np.sort(lst) 

 

會得到:

  1. 1000 loops, best of 3:350 µs per loop 

我們現在比最初的基準測試快 52 倍!Julia 在該基準測試上花費了 419 微秒,因此編譯的 Python 快 20%。

我知道,一些讀者會說我不會進行同類比較。我不同意。請記住,我們現在的任務是使用主機語言以***的方式排序輸入數組。在這種情況下,***方法是使用一個內置的函數。

剖析代碼

我們現在來看看第三個示例,計算 Mandelbrodt 集。Julia 團隊使用了這段 Python 代碼:

  1. def mandel(z): 
  2.  
  3.     maxiter = 80 
  4.  
  5.     c = z 
  6.  
  7.     for n in range(maxiter): 
  8.  
  9.         if abs(z) > 2: 
  10.  
  11.             return n 
  12.  
  13.         z = z*z + c 
  14.  
  15.      return maxiter 
  16.  
  17.  
  18. def mandelperf(): 
  19.  
  20.     r1 = np.linspace(-2.0, 0.5, 26) 
  21.  
  22.     r2 = np.linspace(-1.0, 1.0, 21) 
  23.  
  24.     return [mandel(complex(r, i)) for r in r1 for i in r2] 
  25.  
  26.   
  27.  
  28. assert sum(mandelperf()) == 14791 

 

***一行是一次合理性檢查。對 mandelperf() 函數計時會得到:

  1. 100 loops, best of 3:4.62 ms per loop 

使用 Cython 會得到:

  1. 100 loops, best of 3:1.94 ms per loop 

還不錯,但我們可以使用 Numba 做得更好。不幸的是,Numba 還不會編譯列表推導式 (list

comprehension)。因此,我們不能將它應用到第二個函數,但我們可以將它應用到***個函數。我們的代碼類似以下代碼。

  1. @jit 
  2.  
  3. def mandel_numba(z): 
  4.  
  5.     maxiter = 80 
  6.  
  7.     c = z 
  8.  
  9.     for n in range(maxiter): 
  10.  
  11.         if abs(z) > 2: 
  12.  
  13.             return n 
  14.  
  15.         z = z*z + c 
  16.  
  17.      return maxiter 
  18.  
  19. def mandelperf_numba(): 
  20.  
  21.     r1 = np.linspace(-2.0, 0.5, 26) 
  22.  
  23.     r2 = np.linspace(-1.0, 1.0, 21) 
  24.  
  25.     return [mandel_numba(complex(r, i)) for r in r1 for i in r2] 

 

對它計時會得到:

  1. 1000 loops, best of 3:503 µs per loop 

還不錯,比 Cython 快 4 倍,比最初的 Python 代碼快 9 倍!

我們還能做得更好嗎?要知道是否能做得更好,一種方式是剖析代碼。內置的 %prun 剖析器在這里不夠精確,我們必須使用一個稱為 line_profiler 的更好的剖析器。它可以通過pip 進行安裝:

  1. pip install line_profiler 

安裝后,我們需要加載它:

  1. %load_ext line_profiler 

然后使用一個神奇的命令剖析該函數:

  1. %lprun -s -f mandelperf_numba mandelperf_numba() 

它在一個彈出窗口中輸出以下信息。

  1. Timer unit:1e-06 s 
  2.  
  3. Total time:0.003666 s 
  4.  
  5. File: 
  6.  
  7. Function: mandelperf_numba at line 11 
  8.  
  9. Line # Hits Time Per Hit % Time Line Contents 
  10.  
  11. ============================================================== 
  12.  
  13. 11 def mandelperf_numba(): 
  14.  
  15. 12 1 1994 1994.0 54.4 r1 = np.linspace(-2.0, 0.5, 26) 
  16.  
  17. 13 1 267 267.0 7.3 r2 = np.linspace(-1.0, 1.0, 21) 
  18.  
  19. 14 1 1405 1405.0 38.3 return [mandel_numba(complex(r, i)) for r in r1 for i in r2] 

 

我們看到,大部分時間都花費在了 mandelperf_numba() 函數的***行和***一行上。***一行有點復雜,讓我們將它分為兩部分來再次剖析:

  1. def mandelperf_numba(): 
  2.  
  3.     r1 = np.linspace(-2.0, 0.5, 26) 
  4.  
  5.     r2 = np.linspace(-1.0, 1.0, 21) 
  6.  
  7.     c3 = [complex(r, i) for r in r1 for i in r2] 
  8.  
  9.     return [mandel_numba(c) for c in c3] 

 

剖析器輸出變成:

  1. Timer unit:1e-06 s 
  2.  
  3. Total time:0.002002 s 
  4.  
  5. File: 
  6.  
  7. Function: mandelperf_numba at line 11 
  8.  
  9. Line # Hits Time Per Hit % Time Line Contents 
  10.  
  11. ============================================================== 
  12.  
  13. 11 def mandelperf_numba(): 
  14.  
  15. 12 1 678 678.0 33.9 r1 = np.linspace(-2.0, 0.5, 26) 
  16.  
  17. 13 1 235 235.0 11.7 r2 = np.linspace(-1.0, 1.0, 21) 
  18.  
  19. 14 1 617 617.0 30.8 c3 = [complex(r, i) for r in r1 for i in r2] 
  20.  
  21. 15 1 472 472.0 23.6 return [mandel_numba(c) for c in c3] 

 

我們可以看到,對函數 mandel_numba() 的調用僅花費了總時間的 1/4。剩余時間花在 mandelperf_numba()

函數上。花時間優化它是值得的。

再次使用 Numpy

使用 Cython 在這里沒有太大幫助,而且 Numba 不適用。擺脫此困境的一種方法是再次使用 Numpy。我們將以下代碼替換為生成等效結果的 Numpy

代碼。

  1. return [mandel_numba(complex(r, i)) for r in r1 for i in r2] 

此代碼構建了所謂的二維網格。它計算由 r1 和 r2 提供坐標的點的復數表示。點 Pij 的坐標為 r1[i] 和 r2[j]。Pij 通過復數 r1[i] +

1j*r2[j] 進行表示,其中特殊常量 1j 表示單個虛數 i。

我們可以直接編寫此計算的代碼:

 

  1. @jit 
  2.  
  3. def mandelperf_numba_mesh(): 
  4.  
  5.     width = 26 
  6.  
  7.     height = 21 
  8.  
  9.     r1 = np.linspace(-2.0, 0.5, width) 
  10.  
  11.     r2 = np.linspace(-1.0, 1.0, height) 
  12.  
  13.     mandel_set = np.zeros((width,height), dtype=int
  14.  
  15.     for i in range(width): 
  16.  
  17.         for j in range(height): 
  18.  
  19.             mandel_set[i,j] = mandel_numba(r1[i] + 1j*r2[j]) 
  20.  
  21.      return mandel_set 

 

請注意,我將返回值更改為了一個二維整數數組。如果要顯示結果,該結果與我們需要的結果更接近。

對它計時會得到:

  1. 10000 loops, best of 3:140 µs per loop 

我們比最初的 Python 代碼快約 33 倍!Julia 在該基準測試上花費了 196 微秒,因此編譯的 Python 快 40%。

向量化

讓我們來看另一個示例。老實地講,我不確定要度量什么,但這是 Julia 團隊使用的代碼。

  1. def parse_int(t): 
  2.  
  3.     for i in range(1,t): 
  4.  
  5.         n = random.randint(0,2**32-1) 
  6.  
  7.         s = hex(n) 
  8.  
  9.         if s[-1]=='L'
  10.  
  11.             s = s[0:-1] 
  12.  
  13.         m = int(s,16) 
  14.  
  15.         assert m == n 
  16.  
  17.     return n 

 

實際上,Julia 團隊的代碼有一條額外的指令,用于在存在末尾的 ‘L’ 時刪除它。我的 Anaconda 安裝需要這一行,但我的 Python 3安裝不需要它,所以我刪除了它。最初的代碼是:

  1. def parse_int(t): 
  2.  
  3.     for i in range(1,t): 
  4.  
  5.         n = random.randint(0,2**32-1) 
  6.  
  7.         s = hex(n) 
  8.  
  9.         if s[-1]=='L'
  10.  
  11.             s = s[0:-1] 
  12.  
  13.         m = int(s,16) 
  14.  
  15.         assert m == n 
  16.  
  17.     return n 

 

對修改后的代碼計時會得到:

  1. 100 loops, best of 3:3.33 ms per loop 

Numba 似乎沒什么幫助。Cython 代碼運行速度快了約 5 倍:

  1. 1000 loops, best of 3:617 µs per loop 

Cython 代碼運行速度快了約 5 倍,但這還不足以彌補與 Julia 的差距。

我對此基準測試感到迷惑不解,我剖析了最初的代碼。以下是結果:

  1. Timer unit:1e-06 s 
  2.  
  3. Total time:0.013807 s 
  4.  
  5. File: 
  6.  
  7. Function: parse_int at line 1 
  8.  
  9. Line # Hits Time Per Hit % Time Line Contents 
  10.  
  11. ============================================================== 
  12.  
  13. 1 def parse_int(): 
  14.  
  15. 2 1000 699 0.7 5.1 for i in range(1,1000): 
  16.  
  17. 3 999 9149 9.2 66.3 n = random.randint(0,2**32-1) 
  18.  
  19. 4 999 1024 1.0 7.4 s = hex(n) 
  20.  
  21. 5 999 863 0.9 6.3 if s[-1]=='L'
  22.  
  23. 6 s = s[0:-1] 
  24.  
  25. 7 999 1334 1.3 9.7 m = int(s,16) 
  26.  
  27. 8 999 738 0.7 5.3 assert m == n 

 

可以看到,大部分時間都花費在了生成隨機數上。我不確定這是不是該基準測試的意圖。

加速此測試的一種方式是使用 Numpy 將隨機數生成移到循環之外。我們一次性創建一個隨機數數組。

  1. def parse_int_vec(): 
  2.  
  3.     n = np.random.randint(0,2**32-1,1000) 
  4.  
  5.         for i in range(1,1000): 
  6.  
  7.             ni = n[i] 
  8.  
  9.             s = hex(ni) 
  10.  
  11.         m = int(s,16) 
  12.  
  13.         assert m == ni 

 

對它計時會得到:

  1. 1000 loops, best of 3:848 µs per loop 

還不錯,快了 4 倍,接近于 Cython 代碼的速度。

擁有數組后,通過循環它來一次向某個元素應用 hex() 和 int() 函數似乎很傻。好消息是,Numpy 提供了一種向數組應用函數的方法,而不必使用循環,該函數是numpy.vectorize() 函數。此函數接受一次處理一個對象的函數。它返回一個處理數組的新函數。

  1. vhex = np.vectorize(hex) 
  2.  
  3. vint = np.vectorize(int
  4.  
  5. def parse_int_numpy(): 
  6.  
  7.     n = np.random.randint(0,2**32-1,1000) 
  8.  
  9.     s = vhex(n) 
  10.  
  11.     m = vint(s,16) 
  12.  
  13.     np.all(m == n) 
  14.  
  15.     return s 

 

此代碼運行速度更快了一點,幾乎像 Cython 代碼一樣快:

  1. 1000 loops, best of 3:703 µs per loop 

我肯定 Python 專家能夠比我在這里做得更好,因為我不太熟悉 Python 解析,但這再一次表明避免 Python 循環是個不錯的想法。

結束語

上面介紹了如何加快 Julia 團隊所使用的 4 個示例的運行速度。還有 3 個例子:

  • pisum 使用 Numba 的運行速度快 29 倍。
  • randmatstat 使用 Numpy 可將速度提高 2 倍。
  • randmatmul 很簡單,沒有工具可應用到它之上。

包含所有 7 個示例的完整代碼的 Notebook 可在此處獲得。

我們在一個表格中總結一下我們的結果。我們給出了在最初的 Python 代碼與優化的代碼之間實現的加速。我們還給出了對 Julia 團隊使用的每個基準測試示例使用的工具。

 

 

這個表格表明,在前 4 個示例中,優化的 Python 代碼比 Julia 更快,后 3 個示例更慢。請注意,為了公平起見,對于 Fibonacci,我使用了遞歸代碼。

我認為這些小型的基準測試沒有提供哪種語言最快的明確答案。舉例而言, randmatstat 示例處理 5×5 矩陣。使用 Numpy 數組處理它有點小題大做。應該使用更大的矩陣執行基準測試。

我相信,應該在更復雜的代碼上對語言執行基準測試。Python 與 Julia 比較–一個來自機器學習的示例中提供了一個不錯的示例。在該文章中,Julia 似乎優于 Cython。如果我有時間,我會使用 Numba試一下。

無論如何,可以說,在這個小型基準測試上,使用正確的工具時,Python 的性能與 Julia 的性能不相上下。相反地,我們也可以說,Julia 的性能與編譯后的

Python 不相上下。考慮到 Julia 不需要對代碼進行任何注釋或修改,所以這本身就很有趣。

補充說明

我們暫停一會兒。我們已經看到在 Python 代碼性能至關重要時,應該使用許多工具:

  • 使用 line_profiler 執行剖析。
  • 編寫更好的 Python 代碼來避免不必要的計算。
  • 使用向量化的操作和通過 Numpy 來廣播。
  • 使用 Cython 或 Numba 編譯。

使用這些工具來了解它們在哪些地方很有用。與此同時,請謹慎使用這些工具。分析您的代碼,以便可以將精力放在值得優化的地方。重寫代碼來讓它變得更快,有時會讓它難以理解或通用性降低。因此,僅在得到的加速物有所值時這么做。Donald Knuth 曾經恰如其分地提出了這條建議:

“我們在 97% 的時間應該忘記較小的效率:不成熟的優化是萬惡之源。”

但是請注意,Knuth 的引語并不意味著優化是不值得的,例如,請查看停止錯誤地引用 Donald Knuth 的話!和‘不成熟的優化是惡魔’的謊言。

Python 代碼可以優化,而且應該在有意義的時間和位置進行優化。 

責任編輯:龐桂玉 來源: Python開發者
相關推薦

2013-07-05 14:59:50

程序員GPU

2011-10-24 13:07:00

2023-05-23 13:59:41

RustPython程序

2013-12-17 09:02:03

Python調試

2013-12-31 09:19:23

Python調試

2013-08-22 10:17:51

Google大數據業務價值

2015-03-16 12:50:44

2009-12-08 18:06:12

戴爾存儲動車組

2025-05-19 08:24:29

圖片加載開發

2017-07-03 15:56:44

自主運行的網絡瞻博網絡

2020-08-25 08:56:55

Pythonawk字符串

2009-12-08 14:26:13

大型網絡運維

2021-05-20 08:37:32

multiprocesPython線程

2011-10-27 09:42:19

ASP.NET

2022-10-21 13:52:56

JS 報錯調試本地源碼

2023-04-05 14:19:07

FlinkRedisNoSQL

2021-10-02 10:36:00

YAML編程語言軟件開發

2012-10-26 12:33:58

視頻會議視頻通信華為

2021-09-07 10:29:11

JavaScript模塊CSS

2021-04-13 22:30:17

SpringBoot日志微服務
點贊
收藏

51CTO技術棧公眾號

国产亚洲欧美精品久久久www| 一本一道久久a久久精品综合 | 91免费视频网址| 欧美激情亚洲自拍| 超碰caoprom| 欲香欲色天天天综合和网| 91麻豆国产香蕉久久精品| 琪琪第一精品导航| 一级片黄色录像| 日本精品视频| 欧美日韩国产精品一区二区不卡中文| 免费在线成人av| 亚洲天堂男人网| 欧美视频成人| 亚洲人免费视频| 亚洲精品视频三区| 美女网站在线看| 国产欧美精品国产国产专区| 日韩av免费在线看| 久久久久久久久久97| 国产精品网在线观看| 精品久久久久久久久久久久久久| 日本在线观看一区| 高潮毛片又色又爽免费| 天天操综合网| 日韩精品中文字幕在线| 天天操天天干天天做| heyzo一区| 日本一区二区在线不卡| 国产福利久久| 中文在线字幕av| 激情久久一区| 自拍偷拍免费精品| 疯狂揉花蒂控制高潮h| 国产欧美88| 91久久奴性调教| 成人免费视频91| 日本视频在线免费观看| 99在线精品一区二区三区| 国产欧美久久久久久| 亚洲精品午夜国产va久久成人| 久久伦理在线| 亚洲欧洲美洲在线综合| 中文字幕一区二区三区四| 国产精品av一区二区三区| 一区二区三区欧美亚洲| 日本不卡一二三区| 五月婷婷在线观看视频| 国产高清视频一区| 国产噜噜噜噜噜久久久久久久久 | 色老头一区二区| 亚洲日韩成人| 欧美国产欧美亚洲国产日韩mv天天看完整| 性の欲びの女javhd| 都市激情亚洲| 日韩你懂的在线观看| 最新免费av网址| 91国内外精品自在线播放| 天天综合日日夜夜精品| 中文字幕日韩精品无码内射| 麻豆tv免费在线观看| 国产色婷婷亚洲99精品小说| 韩国成人一区| 日韩一级中文字幕| 国产成人一级电影| 91久久偷偷做嫩草影院| jizz国产视频| 国产麻豆视频精品| 亚洲jizzjizz日本少妇| 国产又粗又猛又爽又黄视频| 日本不卡中文字幕| 国产精品国产亚洲伊人久久| 日韩网站在线| 欧美伊人精品成人久久综合97| 欧美三级在线观看视频| 伦xxxx在线| 亚洲日本在线a| 伊人网在线免费| 污视频在线免费观看网站| 亚洲激情第一区| 日本国产中文字幕| xxxx成人| 欧美日韩视频免费播放| 欧美色图另类小说| 人人鲁人人莫人人爱精品| 日本大香伊一区二区三区| 黄色片在线免费| a一区二区三区亚洲| 欧美自拍偷拍一区| 一本色道久久亚洲综合精品蜜桃| 成人免费av电影| 欧洲色大大久久| 午夜啪啪小视频| 成人av动漫| 亚洲免费小视频| 一二三四在线观看视频| 最新精品国产| 97国产精品视频| 成人h动漫精品一区二区下载| 日韩黄色片在线观看| 国产欧美韩国高清| 亚洲第一色视频| www国产成人免费观看视频 深夜成人网| 精品日韩欧美| 超碰免费97在线观看| 一区免费观看视频| 日本中文字幕一级片| 美女的胸无遮挡在线观看| 91九色最新地址| 国产高清av片| 日韩理论电影中文字幕| 中文字幕日韩专区| 久久综合成人网| 99热精品在线观看| 成人av在线网址| 香蕉久久国产av一区二区| 中文字幕电影一区| 亚洲色成人www永久在线观看 | 久久久成人免费视频| 男女性色大片免费观看一区二区| 147欧美人体大胆444| 青青草娱乐在线| 国产精品久久久久久久久免费相片| 色哺乳xxxxhd奶水米仓惠香| av福利导福航大全在线| 狠狠色狠狠色综合日日五| 五月天av在线播放| 日韩超碰人人爽人人做人人添| 中文字幕不卡av| av资源吧首页| 国产做a爰片久久毛片| 国产一区二区久久久| lutube成人福利在线观看| 日韩一区在线看| 国产男女无遮挡| 超碰精品在线观看| 久久国产精品电影| 中文字幕精品无码亚| 99re热这里只有精品免费视频 | 精品国产午夜福利在线观看| 色综合中文网| 国内精品久久久久伊人av| 97精品久久人人爽人人爽| 久久网这里都是精品| 国产 欧美 日韩 一区| 欧美日韩视频免费看| 日韩激情av在线免费观看| 国产美女福利视频| 男人的j进女人的j一区| 欧美一区国产一区| 激情黄产视频在线免费观看| 欧美刺激脚交jootjob| ass极品国模人体欣赏| 另类国产ts人妖高潮视频| 国产偷国产偷亚洲高清97cao| 成人午夜在线影视| 欧美在线免费观看亚洲| 无码人妻精品一区二区三应用大全| 欧美日韩99| 91久久偷偷做嫩草影院| 18加网站在线| 日韩一级片网站| 91麻豆免费视频网站| 久88久久88久久久| 亚洲午夜精品久久久中文影院av| 人人视频精品| 亚洲欧美变态国产另类| 国产精品va无码一区二区三区| 99久久婷婷国产| 欧美视频在线免费播放| 精品av导航| 欧美成人中文字幕在线| 91麻豆国产视频| 亚洲欧美在线高清| 午夜影院免费观看视频| 欧美a级在线| av一本久道久久波多野结衣| 牛牛精品在线视频| 亚洲成人999| 亚洲精品国产精品乱码| 91麻豆国产福利在线观看| 日韩久久一级片| 欧美男gay| 欧美一区二区三区……| 极品美乳网红视频免费在线观看 | 国产精品一二三产区| 亚洲成av人乱码色午夜| 国产香蕉在线视频| 91小视频在线观看| 国产三级日本三级在线播放| 欧美xxav| 99在线视频免费观看| 亚洲制服国产| 亚洲高清色综合| 久久露脸国语精品国产91| 久久综合久久综合久久综合| 亚洲色图久久久| 99精品美女| 国产精华一区| 69久成人做爰电影| 中文字幕欧美亚洲| www.超碰在线.com| 第一福利永久视频精品| 国产午夜精品久久久久久久久| 久久国产综合精品| 97免费视频观看| 免费视频一区三区| 91九色国产视频| 女人让男人操自己视频在线观看 | 亚洲激情图片qvod| 精品黑人一区二区三区观看时间| 日韩成人午夜精品| www.国产二区| 精品成人影院| 国产伦一区二区三区色一情| 国产91精品在线| 97精品国产97久久久久久免费| 欧美精品少妇| 日韩区在线观看| 亚洲天堂五月天| 亚洲国产精品一区二区www| 午夜时刻免费入口| 精品一区二区影视| 日韩精品xxxx| 一区二区三区日本久久久 | 在线观看免费黄色片| 香蕉久久精品| 999精品视频一区二区三区| av老司机免费在线| 最近的2019中文字幕免费一页| 免费看日韩av| 欧美一区二区三区在线观看视频| 99精品人妻国产毛片| 一区二区三区不卡视频在线观看| 欧美激情视频二区| 久久综合九色综合97_久久久| 日本黄色一级网站| 美女一区二区三区| 麻豆传传媒久久久爱| 亚洲黑丝一区二区| 青青视频免费在线| 偷拍欧美精品| 亚洲国产精品综合| 国产一区二区在线| 久久久久久久久一区二区| www.神马久久| av成人午夜| 日日夜夜一区| 国产精品一区二区三区久久| 免费电影日韩网站| 91大神福利视频在线| 日本在线观看高清完整版| 久久香蕉国产线看观看av| 日本中文字幕在线视频| 亚洲香蕉成视频在线观看| 亚洲aⅴ在线观看| 欧美日韩中文另类| 天天综合久久综合| 黑人狂躁日本妞一区二区三区 | 亚洲精品成人精品456| 天堂网av2018| 中文字幕av一区 二区| 中文字幕一二三四区| 26uuu国产电影一区二区| 少妇精品一区二区三区| 99久久免费国产| 在线精品一区二区三区| 91亚洲资源网| www.欧美com| 美女视频网站久久| 毛片毛片毛片毛| 蜜桃精品视频在线观看| 久久美女福利视频| 老牛影视一区二区三区| 成人黄色一区二区| 日本不卡高清视频| 黄色在线视频网| 卡一卡二国产精品| 99999精品| 国产v日产∨综合v精品视频| 第一页在线视频| 99精品久久99久久久久| 日韩网站在线播放| 欧美激情一区二区三区不卡| 人妻无码一区二区三区免费| 中文字幕一区二区视频| 国产精品久久久久久久精| 亚洲线精品一区二区三区八戒| 日本高清www免费视频| 日韩欧美成人免费视频| 一本一道人人妻人人妻αv| 91麻豆精品国产91久久久使用方法| 国产色在线视频| 51精品秘密在线观看| 99热这里只有精品9| 91精品国产高清一区二区三区| 丰满人妻熟女aⅴ一区| 亚洲久久久久久久久久久| 成人免费在线电影| 欧美成人高清视频| 国产污视频在线播放| 日韩美女写真福利在线观看| 欧美午夜三级| 国产精品一区二区a| 女人丝袜激情亚洲| 四虎影院一区二区| 亚洲韩日在线| 国产精品区在线| 国产精品自拍一区| 香蕉网在线播放| 亚洲精品成人少妇| 无码视频在线观看| 日韩欧美中文字幕精品| 欧美女同网站| 欧美黑人巨大xxx极品| japanese23hdxxxx日韩| 亚洲自拍欧美另类| 中文有码一区| 国产精品免费看久久久无码| 久久久久久久波多野高潮日日| 手机av在线免费| 久久综合狠狠综合久久综合88| 搜索黄色一级片| 色偷偷久久人人79超碰人人澡| 国产免费高清视频| 亚洲日韩欧美视频一区| 亚洲大胆人体大胆做受1| 国产99久久精品一区二区| 日本在线一区二区三区| 欧美一区二区三区四区五区六区 | 久久99九九| 亚洲色图欧美| 欧美一级特黄a| 26uuu久久天堂性欧美| 精品国产乱码久久久久久鸭王1 | 国产一级片免费| 欧美麻豆精品久久久久久| 日本国产在线| 国内免费精品永久在线视频| 精品入口麻豆88视频| 午夜午夜精品一区二区三区文| 制服诱惑一区二区| 日本道中文字幕| 一区二区在线电影| 91精品在线视频观看| 亚洲午夜精品视频| 午夜激情电影在线播放| 国产一区精品视频| 欧美日韩精选| 日本网站在线看| 中文字幕在线不卡| 最新国产中文字幕| 亚洲男人av在线| 第一福利在线视频| 国产chinese精品一区二区| 综合久久久久| 国产无色aaa| 国产精品久久久久天堂| 中文文字幕一区二区三三| 一区二区三区视频在线| 三上悠亚激情av一区二区三区 | 国偷自拍第113页| 亚洲福利小视频| 国产理论在线| 国产精品播放| 亚洲激情网址| 在线精品视频播放| 午夜精品久久久久久久99水蜜桃| 黄色av网站免费在线观看| 久久久久久久97| 欧美亚洲色图校园春色| 午夜免费福利小电影| 91亚洲精华国产精华精华液| 狠狠躁夜夜躁人人爽天天高潮| 日韩精品中文字幕一区二区三区| 亚洲区欧洲区| 国产乱人伦精品一区二区| 亚洲伦理精品| 久久精品—区二区三区舞蹈| 在线观看日产精品| 色呦呦在线观看视频| 久久国产精品免费一区| 毛片av一区二区| 日本熟妇毛耸耸xxxxxx| 国产亚洲综合久久| 一区二区三区在线资源| 国产成人亚洲精品无码h在线| 国产精品成人一区二区三区夜夜夜 | 精品国产99久久久久久| 国产美女99p| 麻豆视频一区二区| 精品一区在线视频| 中文字幕欧美日韩在线| 老牛影视av一区二区在线观看| 伊人国产在线视频| 欧美日韩一区二区三区 | 91精品91久久久久久| 久久国产亚洲精品| 亚洲av成人片色在线观看高潮| 欧美日韩高清一区二区不卡|