5種帶你輕松分析Python代碼的軟件庫
譯文【51CTO.com快譯】通常,人們會使用兩種速度來衡量某種編程語言的優(yōu)劣,即:開發(fā)速度和執(zhí)行速度。對于Python而言,大家往往受益的是它能夠快速地編寫代碼,而忽略了它是否能夠快速地運行,并及時完成既定的任務。因此,在出現(xiàn)程序運行緩慢時,我們有必要從代碼層面上,找出拖慢的位置和原因,并對其進行處理。
好消息是,Python提供了許多不同用途的軟件庫,可方便我們對應用代碼進行分析,并找出導致緩慢運行的部分。它們中,有的是只帶有標準庫的單行工具,有的是可以從運行程序中收集到統(tǒng)計信息的復雜框架。下面,我將向您介紹其中五個可以在PyPI或Python標準庫中輕松獲得,且能夠跨平臺運行的軟件庫。
1.Time和Timeit
有時候,您可能只想分析兩個代碼段從前一個結(jié)束到下一個開始運行,是需要幾秒鐘還是幾分鐘。對于這樣的需求,您可能只需要一個秒表就足夠了。
Python標準庫帶有兩個可用作秒表的功能函數(shù)。其中,Time模塊具有perf_counter功能。它可以調(diào)用操作系統(tǒng)的高精度定時器,以按需獲得時間戳。其基本原理是:我們可以在目標操作開始前,調(diào)用一次time.perf_counter,然后在操作完成時,再調(diào)用一次,以獲得兩次的時間差。顯然,這是一種非常簡便易行的時間獲取方式。
而Timeit模塊則是會對Python代碼進行實質(zhì)性的審查。它的timeit.timeit功能函數(shù)會截取一個代碼段,通過運行多次(默認為1百萬次),以獲得執(zhí)行該操作所需的平均時間。我們經(jīng)??梢杂盟鼇泶_定在某個緊密的循環(huán)中,單一操作或函數(shù)的調(diào)用時長。例如,如果您想判定一個列表解析式(list comprehension)與一個常規(guī)列表結(jié)構,哪個在執(zhí)行多次操作時會更快一些(列表解析式通常更快)。
當然,Time的不足之處在于它只是一個秒表,而Timeit的不足之處在于:其主要用例是各個行或代碼塊上的各個細微標準差(microbenchmarks)。也就是說,僅當這些代碼被單獨處理時,這種比較才會有意義。因此,這兩種方法都不足以對整個程序進行分析。一旦出現(xiàn)數(shù)千行的代碼,這兩種方法都會耗費您大量的時間。
2.cProfile
Python標準庫還帶有一個整體程序分析器--cProfile。在程序運行時,cProfile會通過跟蹤代碼中的每個函數(shù)的調(diào)用,以生成一個包含了最常調(diào)用函數(shù)、以及平均調(diào)用時間的列表。
cProfile具有三大優(yōu)勢:
- 由于它被包含在標準庫中,因此現(xiàn)有的Python安裝包已經(jīng)包含了cProfile。
- 它可以分析有關調(diào)用行為的許多不同統(tǒng)計信息。例如:它能夠?qū)⒑瘮?shù)調(diào)用自己的指令所花費的時間,與該函數(shù)所有的其他調(diào)用耗時區(qū)分開來。據(jù)此,您可以判定出到底是該函數(shù)本身運行緩慢,還是在其他調(diào)用時出現(xiàn)的緩慢。
- 可以實現(xiàn)限定條件的自定義。也就是說,您既可以對整個程序的運行進行采樣,又可以僅在指定的函數(shù)運行時啟用概要分析(toggle profiling)。通過縮小范圍和去除分析時產(chǎn)生的“噪聲”,您可以更好地關注該函數(shù)的功能與調(diào)用。
cProfile的不足之處有:
- 默認情況下,它會設置多個采集點,生成大量的統(tǒng)計信息。
- 根據(jù)其執(zhí)行模型,它在捕獲每個函數(shù)調(diào)用時,都會產(chǎn)生大量的流量。因此cProfile不適合通過實時數(shù)據(jù)的方式,對生產(chǎn)環(huán)境中的應用程序進行性能分析。也就是說,它更適合于針對開發(fā)過程中的性能分析。
3.Pyinstrument
與cProfile的工作方式類似,Pyinstrument能夠通過跟蹤目標程序,以報告的形式,反映出那些占用了大部分運行時間的代碼。不過,與cProfile相比,Pyinstrument的優(yōu)點主要體現(xiàn)在如下兩個方面:
- Pyinstrument不會去勾連(hook)函數(shù)調(diào)用的每個實例,而是會以毫秒為間隔,對程序的調(diào)用棧進行采樣,因此它能夠靈敏地檢測出程序中最耗費運行時的部分。
- Pyinstrument的報告要簡潔得多。它能夠通過突出顯示程序中占用時間最多的函數(shù),以便您能盡快地發(fā)現(xiàn)問題,并專注分析原因。
Pyinstrument同樣具有cProfile的各種優(yōu)點。您可以將它用作應用程序中的對象,來記錄所選功能,而不是整個程序的行為。Pyinstrument提供包括HTML格式在內(nèi)的多種輸出形式。當然,您也可以按需查看各個調(diào)用的完整時間線。
此外,如下兩個方面值得您的注意:
- 某些通過C編譯的擴展程序(例如使用Cython創(chuàng)建的程序),會在通過命令行進行Pyinstrument調(diào)用時,可能無法正常工作。不過,如果您在程序本身使用了Pyinstrument,例如:通過使用Pyinstrument分析器的調(diào)用包裝了main()函數(shù),那么它們還是能夠正常工作的。
- Pyinstrument不能很好地處理在多個線程中運行的代碼。此時,您可能需要考慮使用下面將要介紹到的Py-spy。
4.Py-spy
與Pyinstrument一樣,Py-spy在工作原理上,也是定期采集程序調(diào)用棧的狀態(tài),而不是記錄每一個調(diào)用。不過,與PyInstrument不同,Py-spy帶有用Rust編寫的核心組件(而Pyinstrument使用的是C擴展程序),運行的是帶有分析程序的外進程(out-of-process),因此它可以安全地與生產(chǎn)環(huán)境中的代碼協(xié)同使用。
Py-spy能夠輕松地完成許多其他分析工具無法實現(xiàn)的任務,其中包括:分析多線程或帶有子處理(subprocessed)機制的Python程序等。此外,Py-spy也可以分析那些使用符號進行過編譯的C擴展程序。而對于使用了Cython編譯的擴展程序,Py-spy需要使用對應生成的C文件,以便收集正確的跟蹤信息。
我們可以使用如下兩種基本方法,來利用Py-spy檢查應用程序:
- 使用Py-spy的record命令,并在運行結(jié)束后會生成火焰圖(flame graph)。
- 使用Py-spy的top命令,通過實時更新,交互式地顯示Python應用程序的內(nèi)部,并以與Unix的top工具相同的方式顯示信息。而且那些單線程棧也可以通過命令行被顯示出來。
不過,Py-spy的最大缺點之一是:它主要適用于從外部分析整個程序、或是某些組件,不適合對某個特定的功能函數(shù)進行采樣。
5.Yappi
Yappi是Yet Another Python Profiler(“另一個Python分析工具”)的縮寫。它在功能上,較上述討論過的工具庫只多不少。在默認情況下,PyCharm(譯者注:一款為專業(yè)Python 開發(fā)人員準備的IDE)會已安裝了Yappi,因此用戶在IDE中已經(jīng)具有了對于Yappi的內(nèi)置訪問權限。
要使用Yappi,您需要用指令來“修飾”目標代碼,以便針對分析機制進行調(diào)用,啟動,停止和生成報告。Yappi允許您根據(jù)測試的實際需求,在“經(jīng)過時間(wall time)”或“CPU時間”之間進行選擇。前者只是一個秒表;后者則可以通過系統(tǒng)原生API,記錄下CPU在實際執(zhí)行代碼過程中的用時,以便調(diào)整I/O的暫?;蚓€程的休眠??梢?,CPU時間能夠方便您更加精確地了解某些操作(例如:數(shù)字代碼的執(zhí)行)的實際用時。
通過Yappi提供的函數(shù)--yappi.get_thread_stats(),您可以記錄任何一個線程活動,檢索出對應的統(tǒng)計信息,并分別對其進行分析。您不但無需“修飾”線程代碼,而且可以對統(tǒng)計數(shù)據(jù)進行過濾和細粒度的排序(類似于cProfile中的此類操作)。
此外,Yappi的獨到之處在于,它可以分析greenlet和coroutine(協(xié)程)。作為一種分析并發(fā)代碼的強大工具,它可以被廣泛地用來分析異步metaphor。
原文標題:5 great libraries for profiling Python code,作者:Serdar Yegulalp
【51CTO譯稿,合作站點轉(zhuǎn)載請注明原文譯者和出處為51CTO.com】