用這 6 種方式優化程式碼,讓你的 Python 速度提升 30%! | TechOrange 科技報橘
Search
Close this search box.

用這 6 種方式優化程式碼,讓你的 Python 速度提升 30%!

【為什麼我們要挑選這篇文章】Python 程式碼直觀容易上手,深受工程師的喜愛,只可惜速度比不上 C 語言。有網友在 Medium 發表一篇文章,教大家如何修改程式碼,讓 Python 速度提升 30%。以下,是加速 Python 的 6 種方式。(責任編輯:郭家宏)

Python 已經得到了全球工程師的喜愛,但是還是遭到一些人的詬病,原因之一就是認為它運作緩慢。

其實某個特定程式(無論使用何種程式語言)的運行速度是快還是慢,在很大程度上取決於編寫該程式的開發人員自身素質,以及他們編寫高效程式碼的能力。

Medium 上一位網友就詳細講了講如何讓 python 提速 30%,以此證明程式碼跑得慢不是 python 的問題,而是程式碼本身的問題。

原文傳送門

首先,找出拖慢程式的程式碼

在開始進行任何優化之前,我們首先需要找出程式碼的哪些部分使整個程式變慢。有時程式的問題很明顯,但是如果你一時不知道問題出在哪裡,那麼這裡有一些可能的選項:

注意:這是我將用於演示的程式,它將進行指數計算(取自 Python 文檔):

▌最簡單的方法:Unix 時間命令

首先,最簡單最偷懶的方法:Unix 時間命令。

如果你只能直到整個程式的運行時間,這樣就夠了,但通常這還遠遠不夠。

▌更詳細的分析:cProfile

另外一個指令是 cProfile,但是它提供的資訊過於詳細了。

(完整程式碼在這裡

在這裡,我們使用 cProfile 模組和 time 參數運行測試腳本,以便按內部時間(cumtime)對行進行排序。這給了我們很多資訊,你在上面看到的行大約是實際輸出的 10%。由此可見,exp 函數是罪魁禍首,現在我們可以更詳細地瞭解時序和性能分析。

▌時序特定功能

現在我們知道了應當主要關注哪裡,我們可能想對運行速度緩慢的函數計時,而不用測量其餘的程式碼。為此,我們可以使用一個簡單的裝飾器:

(完整程式碼在這裡

然後可以將此裝飾器應用於待測功能,如下圖所示:

這給出我們以下輸出:

需要考慮的一件事是我們實際想要測量的時間。時間包提供 time.perf_counter 和 time.process_time 兩個函數。他們的區別在於 perf_counter 返回的絶對值,包括你的 Python 程式進程未運行時的時間,因此它可能會受到電腦負載的影響。另一方面,process_time 僅返回用戶時間(不包括系統時間),這僅是你的過程時間。

加速 Python 的 6 種方式,特定情況可將速度提升 30%

讓 Python 程式運行得更快,這部分會很有趣。我不會展示可以解決你的性能問題的技巧和程式碼,更多地是關於構想和策略的,這些構想和策略在使用時可能會對性能產生巨大影響,在某些情況下,可以將速度提高 30%。

▌使用內置數據類型

這一點很明顯。內置數據類型非常快,尤其是與我們的自定義類型(例如樹或連結列表)相比。這主要是因為內置程式是用 C 實現的,因此在使用 Python 進行編碼時,我們的速度實在無法與之匹敵。

▌使用 lru_cache 緩存/記憶

我已經在上一篇文章中展示了此內容,但我認為值得用簡單的範例來重複它:

上面的函數使用 time.sleep 模擬大量計算。第一次使用參數 1 調用時,它將等待 2 秒鐘,然後才返回結果。再次調用時,結果已經被緩存,因此它將跳過函數的主體並立即返回結果。

▌使用局部變數

這與在每個作用域中查詢變數的速度有關,因為它不只是使用局部變數還是全局變數。實際上,即使在函數的局部變數(最快)、類級屬性(例如 self.name,較慢)和全局(例如導入的函數,如 time.time,最慢)之間,查詢速度實際上也有所不同。

你可以透過使用看似不必要的分配來提高性能,如下所示:

▌使用函數

這似乎違反直覺,因為調用函數會將更多的東西放到堆疊上,並從函數返回中產生開銷,但這與上一點有關。如果僅將整個程式碼放在一個文件中,而不將其放入函數中,則由於全局變數,它的運行速度會慢得多。因此,你可以透過將整個程式碼包裝在 main 函數中,並調用一次來加速程式碼,如下所示:

▌不訪問屬性

可能會使你的程式變慢的另一件事是點運算符號(.),它在獲得對象屬性時被使用。此運算符號使用 __getattribute__ 觸發字典查詢,這會在程式碼中產生額外的開銷。那麼,我們如何才能真正避免(限制)使用它呢?

▌當心字元串

使用模數(% s)或 .format()進行循環運行時,字元串操作可能會變得非常慢。我們有什麼更好的選擇?根據雷蒙德.海廷格(Raymond Hettinger)最近的推特,我們唯一應該使用的是 f 字元串,它是最易讀,最簡潔且最快的方法。根據該推特,這是你可以使用的方法列表——最快到最慢:

生成器本質上並沒有更快,因為它們被允許進行延遲計算,從而節省了記憶體而不是時間。但是,保存的記憶體可能會導致你的程式實際運行得更快。這是怎麼做到的?如果你有一個很大的數據集,而沒有使用生成器(疊代器),那麼數據可能會溢出 CPU L1 緩存,這將大大減慢記憶體中值的查詢速度。

在性能方面,非常重要的一點是 CPU 可以將正在處理的所有數據儘可能地保存在緩存中。你可以觀看 Raymond Hettingers 的影片,他在其中提到了這些問題。

優化的首要規則是不要優化。但是,如果確實需要,那麼我希望上面這些技巧可以幫助你。但是,在優化程式碼時要小心,因為它可能最終使你的程式碼難以閲讀,因此難以維護,這可能超過優化的好處。

(本文經合作夥伴 大數據文摘 授權轉載,並同意 TechOrange 編寫導讀與修訂標題,原文標題為〈代码跑得慢甩锅Python?手把手教你如何给代码提速30%〉。首圖來源:pxfuel CC Licensed

更多寫程式的技巧

上班族自學 Python、機器學習寶典!Kaggle 全新免費課程教你快速入門,且馬上能應用
Python 弱掉了!中國工程師開發「文言文程式語言」,讓你的 coding 充滿文學情懷
【GitHub 年度報告】JavaScript 登最熱門程式語言,Python 首次擊敗 Java 當第二