我有一個負責一個長期執行任務的 Python 指令碼。這個指令碼同其他三個系統通訊 – 它從系統 #1 和 #2 讀取資料,合併它們然後再把它們推送到系統 #3。這是下面的描述。問題是遷移執行在我不滿意的一個地方。因為我想知道該指令碼的大部分工作是在與哪個慢的外部系統進行通訊。Python 有一個非常好用的內建的分析器來回答這類問題。按照這篇文章來學習如何使用它。
分析器(Profiler)
基礎用法非常簡單。假設你有一個 myscript.py
。使用 profiler
執行它,你需要做的是:
1 2 |
$ python -m cProfile -o profile.out myscript.py <other-args> |
它將執行這個指令碼並且 dump 這個 debug 資料到 profile.out。你也可以省略 -o profile.out
來讓統計的 dumped 到指令碼最後的 stdout。
Subprocesses
如果你的指令碼使用了任何 subprocesses,事情就會變得有點複雜。以我來說,我對指令碼的主流程不感興趣 – 它所做的所有事情就是派生(spawn)一些 worker 子程式。我感興趣的是在 worker 中發生了什麼。
讓我們假設你的程式碼與此類似:
1 2 3 4 5 6 7 8 9 10 11 12 |
import multiprocessing import time def worker(num): time.sleep(3) print 'Worker:', num if __name__ == '__main__': for i in range(5): p = multiprocessing.Process(target=worker, args=(i,)) p.start() |
你需要引入另外一個間接層:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
import multiprocessing import cProfile import time def worker(num): time.sleep(3) print 'Worker:', num def profile_worker(num): cProfile.runctx('test(num)', globals(), locals(), 'profile-%d.out' %num) if __name__ == '__main__': for i in range(5): p = multiprocessing.Process(target=profile_worker, args=(i,)) p.start() |
就是這樣。這個指令碼執行之後,你將得到 profile-0.out
到 profile-4.out
這4個檔案。
讀取分析資料
如果你忽略 -o profile.out
這時將在 stdout 得到統計資料。這不是一個完美的解決方案。更好的解決方案是把資料 dump 到檔案中然後使用 runsnake 來分析它。為了在 ubuntu 上安裝它,你需要 wxpython 包,然後你才可以使用 easy-install
安裝它。
1 2 3 |
$ sudo apt-get install python-wxgtk2.8 python-wxtools wx2.8-doc wx2.8-examples wx2.8-headers wx2.8-i18n $ sudo easy-install SquareMap RunSnakeRun |
由於某種原因我沒有在 virtualenv 中執行工作。我需要一個全系統的 easy-install。有人抱怨缺失了 wx
模組。我的系統是 ubuntu 12.04。
然後,就很簡單了:
1 2 |
$ runsnake profile.out |
你在不同的函式獲得了很好的統計分析,呼叫次數和累計時間。這些資料可以告訴你關於你 app 的很多東西。以我而言我獲悉了與其中一個系統通訊花費了 90% 的時間。從那裡開始我可以優化它。
來源