10種檢測Python程式已耗用時間、CPU和記憶體佔用的方法_python

來源:互聯網
上載者:User

在運行複雜的Python程式時,執行時間會很長,這時也許想提高程式的執行效率。但該怎麼做呢?

首先,要有個工具能夠檢測代碼中的瓶頸,例如,找到哪一部分執行時間比較長。接著,就針對這一部分進行最佳化。

同時,還需要控制記憶體和CPU的使用,這樣可以在另一方面最佳化代碼。

因此,在這篇文章中我將介紹7個不同的Python工具,來檢查代碼中函數的執行時間以及記憶體和CPU的使用。
1. 使用裝飾器來衡量函數執行時間

有一個簡單方法,那就是定義一個裝飾器來測量函數的執行時間,並輸出結果:
 

import timefrom functools import wraps def fn_timer(function):  @wraps(function)  def function_timer(*args, **kwargs):    t0 = time.time()    result = function(*args, **kwargs)    t1 = time.time()    print ("Total time running %s: %s seconds" %        (function.func_name, str(t1-t0))        )    return result  return function_timer

接著,將這個裝飾器添加到需要測量的函數之前,如下所示:
 

@fn_timerdef myfunction(...):...

例如,這裡檢測一個函數排序含有200萬個隨機數位數組所需的時間:
 

@fn_timerdef random_sort(n):  return sorted([random.random() for i in range(n)]) if __name__ == "__main__":  random_sort(2000000)

執行指令碼時,會看到下面的結果:
 

Total time running random_sort: 1.41124916077 seconds

2. 使用timeit模組

另一種方法是使用timeit模組,用來計算平均時間消耗。

執行下面的指令碼可以運行該模組。

python -m timeit -n 4 -r 5 -s "import timing_functions" "timing_functions.random_sort(2000000)"

這裡的timing_functions是Python指令檔名稱。

在輸出的末尾,可以看到以下結果:
 

4 loops, best of 5: 2.08 sec per loop

這表示測試了4次,平均每次測試重複5次,最好的測試結果是2.08秒。

如果不指定測試或重複次數,預設值為10次測試,每次重複5次。
3. 使用Unix系統中的time命令

然而,裝飾器和timeit都是基於Python的。在外部環境測試Python時,unix time工具 + 生產力就非常有用。

運行time工具 + 生產力:
 

$ time -p python timing_functions.py

輸出結果為:
 

Total time running random_sort: 1.3931210041 secondsreal 1.49user 1.40sys 0.08

第一行來自預定義的裝飾器,其他三行為:

  •     real表示的是執行指令碼的總時間
  •     user表示的是執行指令碼消耗的CPU時間。
  •     sys表示的是執行核心功能消耗的時間。

注意:根據維基百科的定義,核心是一個電腦程式,用來管理軟體的輸入輸出,並將其翻譯成CPU和其他電腦中的電子裝置能夠執行的資料處理指令。

因此,Real執行時間和User+Sys執行時間的差就是消耗在輸入/輸出和系統執行其他任務時消耗的時間。
4. 使用cProfile模組

如果想知道每個函數和方法消耗了多少時間,以及這些函數被調用了多少次,可以使用cProfile模組。
 

$ python -m cProfile -s cumulative timing_functions.py

現在可以看到代碼中函數的詳細描述,其中含有每個函數調用的次數,由於使用了-s選項(累加),最終結果會根據每個函數的累計執行時間排序。

讀者會發現執行指令碼所需的總時間比以前要多。這是由於測量每個函數的執行時間這個操作本身也是需要時間。
5. 使用line_profiler模組

line_profiler模組可以給出執行每行代碼所需佔用的CPU時間。

首先,安裝該模組:
 

$ pip install line_profiler

接著,需要指定用@profile檢測哪個函數(不需要在代碼中用import匯入模組):
 

@profiledef random_sort2(n):  l = [random.random() for i in range(n)]  l.sort()  return l if __name__ == "__main__":  random_sort2(2000000)

最好,可以通過下面的命令獲得關於random_sort2函數的逐行描述。
 

$ kernprof -l -v timing_functions.py

其中-l表示逐行解釋,-v表示表示輸出詳細結果。通過這種方法,我們看到構建數組消耗了44%的計算時間,而sort()方法消耗了剩餘的56%的時間。

同樣,由於需要檢測執行時間,指令碼的執行時間更長了。
6. 使用memory_profiler模組

memory_profiler模組用來基於逐行測量代碼的記憶體使用量。使用這個模組會讓代碼啟動並執行更慢。

安裝方法如下:

 pip install memory_profiler

另外,建議安裝psutil包,這樣memory_profile會啟動並執行快一點:
 

$ pip install psutil

與line_profiler相似,使用@profile裝飾器來標識需要追蹤的函數。接著,輸入:
 

$ python -m memory_profiler timing_functions.py

指令碼的執行時間比以前長1或2秒。如果沒有安裝psutil包,也許會更長。

從結果可以看出,記憶體使用量是以MiB為單位衡量的,表示的mebibyte(1MiB = 1.05MB)。
7. 使用guppy包

最後,通過這個包可以知道在代碼執行的每個階段中,每種類型(str、tuple、dict等)分別建立了多少對象。

安裝方法如下:
 

$ pip install guppy

接著,將其添加到代碼中:
 

from guppy import hpy def random_sort3(n):  hp = hpy()  print "Heap at the beginning of the functionn", hp.heap()  l = [random.random() for i in range(n)]  l.sort()  print "Heap at the end of the functionn", hp.heap()  return l if __name__ == "__main__":  random_sort3(2000000)

運行代碼:
 

$ python timing_functions.py

可以看到輸出結果為:

通過在代碼中將heap()放置在不同的位置,可以瞭解到指令碼中的對象建立和刪除操作的流程。

如果想學習更多關於Python代碼速度最佳化方面的知識,我建議你去讀這本書《High Performance Python: Practical Performant Programming for Humans, september 2014.》

希望這篇文章能偶幫到你!^_^

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.