讓 python 執行地超快的 10 個方法

pythondict發表於2020-05-08

原文來自Python實用寶典讓python執行地超快的10個方法

大部門人使用python是因為它非常方便,而不是因為它速度快。過多的第三方使得python相比於Java和C的效能差距較大。但也是可以理解的,因為在大部分情況下,開發速度優先於執行速度。

但也不要過於擔心python的速度,這並不一定是一個非此即彼的命題。經過適當優化,Python應用程式可以以驚人的速度執行——也許還不能達到Java或C語言的速度,但是對於Web應用程式、資料分析、管理和自動化工具以及大多數其他用途來說,速度已經足夠快了。快到你可能會忘記了你是在用應用程式效能換取開發人員的生產力。

優化Python效能不能單從一個角度上看。而是應用所有可用的優化方法,並選擇最適合當前場景的多種方法的集合。(Dropbox的員工有一個最令人瞠目的例子,展示了python優化的強大功能,點選連結檢視。)

在本文中,我將簡單講述許多常見的python優化方法。有些是臨時措施,只需要簡單地將一項轉換為另一項(例如更換Python直譯器),但是那些帶來最大收益的方法將需要更詳細的工作。

1. 算速度、算速度、算速度!

如果你不能夠找出速度慢的原因所在,你就不能確定你的python應用程式為什麼執行地不夠理想。

計算的方法有很多,你可以嘗試python內建的 cProfile模組 進行簡單的計算分析,如果需要更高的精度(計算每行語句執行時間),可以使用 line_profiler 第三方工具。通常而言,從計算程式的函式執行時間進行分析就能夠給你提供改進方案,所以推薦使用 profilehooks 第三方,它能計算單個函式的執行時間。

你可能需要更多的挖掘才能發現為什麼你的程式某個地方這麼慢、怎麼修復它。重點在於縮小你的排查範圍,逐漸細化到某條語句上。

2.快取需要重複使用的資料

當你可以把需要計算出來的資料儲存下來的時候,千萬不要重複上千次去計算它。如果你有一個經常需要使用的函式,而且返回的是可預測的結果,Python已經給你提供了一個選項,能將其快取到記憶體中。後續的函式呼叫如果是一樣的,將立即返回結果。

有許多方法都可以做到,比如說:使用python的一個本地:functools,擁有一個裝飾器,叫@functools.lru_cache,它能夠快取函式最近的N個呼叫,當快取的值在特定時間內保持不變的時候這個非常好用,比如說列出最近一天使用的物品。

3.將數學計算重構為NumPy

如果你的Python程式中有基於矩陣或陣列的數學運算,並且希望更高效地對它們進行計算,那麼你就應該使用NumPy,因為它通過使用C來完成繁重的工作,比原生python直譯器能更快得處理陣列,而且能比Python內建資料結構更有效地儲存數字資料。

NumPy還可以極大地加速相對普通的數學運算。該包為許多常見的Python數學操作(如min和max)提供了替換,這些操作的速度比原始Python快很多倍。

NumPy的另一個優點是對大型物件(比如包含數百萬項的列表)能更有效地使用記憶體。一般來說,如果用傳統的Python表示類似於NumPy中的大型物件,那麼它們將佔用大約四分之一的記憶體。

重寫Python演算法以使用NumPy需要做一些工作,因為需要使用NumPy的語法重新宣告陣列物件。但是NumPy在實際的數學操作中使用Python現有的習慣用法(+、-等等),所以切換到NumPy並不會讓人太迷惑。

4.使用C

NumPy使用C編寫的是一種很好的方法。如果現有的C能夠滿足你的需求,那麼Python及其生態系統將提供幾個選項來連線到該庫並利用其提高速度。

最常用的方法是Python的ctypes庫](https://pythondict.com/tag/%e5%ba%93/ “庫”)。因為ctypes與其他Python應用程式廣泛相容,所以它是最好的起點,但也並不是唯一的,CFFI專案為C. Cython提供了一個更優雅的介面(參見下面第五點),也可以用來包裝外部,代價是你必須學習Cython的標記方法。

5.轉換為Cython

如果你非常追求速度,應該用C而不是python,但是對於我這種有python依賴症的人來說,對C天生就有種畏懼。現在有一個很好的解決辦法出來了。

Cython允許Python使用者方便地訪問C的速度。現有的Python程式碼可以逐步轉換為C :首先通過Cython將所述程式碼編譯為C,然後通過新增型別註釋以獲得更快的速度。

不過,Cython不能變魔術。按原樣轉換為Cython的程式碼通常執行速度通常不會加快超過15%到50%,因為該級別的大多數優化都集中在減少Python直譯器的開銷上。只有在為Cython模組提供型別註釋時才允許將相關程式碼轉換為純C,這時候的速度提升才最大。

6.使用多執行緒

由於全域性直譯器鎖(GIL)的存在,Python規定一次只執行一個執行緒,以避免在使用多個執行緒時出現狀態問題。它的存在有充分的理由,但依然很討厭。

隨著時間的推移,GIL的效率顯著提高(這是為什麼你應該用python3的其中一個原因),但是核心問題仍然存在。為了解決這個問題,Python提供了多處理模組(multiprocessing)來在單獨的核心上執行Python直譯器的多個程式。狀態可以通過共享記憶體或伺服器程式共享,資料可以通過佇列或管道在程式例項之間傳遞。

您仍然必須手動管理程式之間的狀態。此外,啟動多個Python例項並在它們之間傳遞物件也會涉及不少開銷。儘管如此,多處理還是很有用的。另外,使用了C的Python模組和包(如NumPy)也是完全避免GIL的。這也是推薦它們提高速度的另一個原因。

7.知道你的正在幹嘛

簡單地輸入import xyz是多麼方便啊,但是你知道,第三方庫雖然可以改變應用程式的效能,但並不總是向好的方向發展。

有時,你加了某個模組的時候,應用程式反而變慢了,這就是來自特定的模組構成瓶頸。同樣,仔細計算執行時間也會有所幫助,有時則不那麼明顯。示例:Pyglet是一個用於建立視窗圖形化應用程式的,它自動啟用除錯模式,這將極大地影響效能,直到顯式禁用為止。除非閱讀文件,否則你可能永遠不會意識到這一點。多讀書,多瞭解情況。

8.意識到平臺間的速度差異

Python的執行是跨平臺的,但這並不意味著每個作業系統(Windows、Linux、OS X)的特性都可以在Python下抽象出來。大多數情況下,你需要了解平臺的細節,比如路徑命名約定等等。

但在效能方面,理解平臺的差異也很重要。例如,有些python指令碼需要使用Windows的api去訪問一些特定的應用,這些應用也可能會減慢執行速度。

9.使用pypy執行程式

CPython是Python最常用的優化方案,因為它優先考慮相容性而不是原始速度。對於那些想把速度放在首位的程式設計師來說,PyPy是一個Python更好的方案,它配備了一個JIT編譯器來加速程式碼的執行(編譯為C程式碼)。

因為PyPy被設計為CPython的一個臨時替代品,所以它是獲得快速效能提升的最簡單方法之一。大多數Python應用程式將完全按原樣執行在PyPy上。然而,充分利用PyPy可能需要不斷地測試。你將會發現,長時間執行的應用程式更有可能從PyPy中獲得了最大的效能收益,因為編譯器會隨著時間分析執行情況。對於執行和退出的簡短指令碼,最好使用CPython,因為效能的提高不足以克服JIT的開銷。

10.升級到python3

如果你用的是python2。而且沒有壓倒一切的理由(比如一個不相容的模組)堅持使用它,你應該跳到python3。

Python 3中還有許多Python 2.x中沒有的構造和優化。例如,Python 3.5使非同步變得不那麼棘手,asyncawait關鍵字成為語言語法的一部分。Python 3.2對全域性直譯器鎖進行了重大升級,顯著改進了Python處理多執行緒的方式。

以上就是全部十點的改進方案啦,儘管使用了這些方法可能執行速度還是無法超過C和Java,但是程式碼跑得快不快,不取決於語言,而是取決於人,況且Python本身不必是最快的,只要足夠快就行。

如果你希望我們今天的Python 教程,請持續關注我們,如果對你有幫助,麻煩在下面點一個贊/在看哦有任何問題都可以在下方留言區留言,我們都會耐心解答的!


​Python實用寶典 (pythondict.com)
不只是一個寶典
歡迎關注公眾號:Python實用寶典

本作品採用《CC 協議》,轉載必須註明作者和本文連結

Python實用寶典, pythondict.com

相關文章