1. 程式人生 > >關於python語言優化的一些思考

關於python語言優化的一些思考

最近一直在做python工程化相關的工作,頗有心得,遂總結一下。
一是為了整理思緒,二是為了解放自己健忘的大腦。

python是一個C的語法糖盒子

原生的python通常都是由cpython實現,而cpython的執行效率,確實讓人不敢恭維,比較好的解決方案有cython、numba、pypy等等

cython

是目前我認為發展最好,最靠譜的一項Python加速解決方案。

使用cython編譯過後的程式碼,通常會對原python程式碼有2倍以上的速度提升。cython的編譯也很簡單,只需要構建一個setup.py,然後執行:

  python setup.py build_ext

numba

numba也是我比較看好的,它的亮點在於使用裝飾器的方式應用jit技術,例如下面的程式碼:

  @jit
  def run_xxx():
    ...

可直接將run_xxx方法進行高效的c編譯。
但在大多數應用場景下(尤其是採取了服務拆分或微服務的架構策略),這種功能反而讓人有種雞肋的感覺

只能說numba更適用於模型開發的場景,在模型應用和部署的環節,numba的作用很尷尬

pypy

pypy相對比較小眾,這是由於它本身的限制條件較多,尤其是對python第三方包的支援上面更是非常侷限。由於我在做python開發的過程中,經常需要限制版本,以及引入較多的第三方包,所以pypy就不在考慮的範圍內了

不要輕易相信聲稱自己很快的模組和方法

曾經在網上看到有人發文,聲稱numpy是目前python下非常高效的一個模組,而numpy的“孃親們”,甚至把自己誇上了天,說自己如何如何高效。而國內的一些偽專家們,也是盲目的“助紂為虐”,說什麼如果你不太懂,請不要輕易去優化numpy云云,難道你自認為優化的演算法能勝過numpy裡內建的久經考驗的演算法?
真的是誤人子弟!很多人在這裡就被唬住了,程式碼分析到numpy的環節,就不敢往下走了。
我想說的是,對一切永遠保持懷疑的精神才是真正的科學素養,是不是真的高效能,一切要用資料說話。
剛開始,我也被短暫的唬住了,畢竟numpy的底層也沒接觸過,但profiler分析的結果告訴我,問題就出在numpy裡,結果發現在我的專案場景裡,使用dict能完全替代numpy的所有操作,效能一下提高了很多,而numpy的高效在於ndarray

所以,採取什麼資料結構要看應用場景,沒有萬能的高效資料結構

不要以為排除法是萬能的

優化程式碼的過程中,因為我的以往成功“經驗”,也導致走了不少彎路,最主要的,就是盲目使用排除法。使用排除法只能使用二分查詢或快排的策略去組織程式碼,如果目的碼比較少還可以,事實上,在真實場景中往往有成百上千行目的碼。人工執行和實現O(logN)量級的操作,似乎是一種蠻幹。

這裡有幾個度量工具順便記錄下:

py_spy

https://github.com/benfred/py-spy
方便的生成CPU執行方法的火焰圖

line_profiler

https://github.com/rkern/line_profiler
逐行程式碼分析,不要小看它的能力,它還可以指定要分析的方法和模組

量變真的會引起質變

在很多人的習慣性邏輯思維裡,一個程式的效能,隨著程式碼的優化,會是一條平滑的增長曲線。但實踐表明,這個邏輯確實有問題。
通過不斷對程式碼的優化,我發現,程式的效能到達一定階段會發生“突變”,或者“階躍”。上一次優化的執行時間幾百毫秒,下一次優化後的執行時間竟然只有幾十毫秒,說發生了“階躍”一點都不誇張。
為什麼會這樣?
至少在我的朋友圈裡,還沒有人能給我令人信服的答案,我自認為比較可靠的理解是,現代作業系統在cpu指令的處理上,對cpu的任務分配還不是那麼“流暢”。
哪位朋友有好的見解,歡迎批評指正!