Python代碼性能調試和優化

2021-01-11 蟲蟲搜奇

一直以來Python性能是遭人詬病的問題之一,抱怨執行慢,沒法用。雖然再性能上語言的差異確實存在著明顯差異,但是我認為一個非常流行的語言,運行的快慢不會成為阻擾人們使用的因素。如果是的話,可能是由於編寫的程序有問題,需要優化。本文蟲蟲就給大家介紹一下如何調試Python應用的性能,以及怎麼對其進行優化。

Python性能調試

要進行Python性能,前提條件是要找出程序中的性能瓶頸。找出程序中影響程序性能的代碼。有經驗的開發者一般都能很容易能找出程序的瓶頸,但對於普通碼農找出系統的問題代碼則很難,為了能快捷有效的發現程序的性能瓶頸就需要進行性能調試,此處我們以一個實際例子進行介紹,以下程序是計算e的x(1..n)次的冪,其代碼如下:

# performance.py

from decimal import *

def exp(x):

getcontext().prec += 2

i, lasts, s, fact, num = 0, 0, 1, 1, 1

while s != lasts:

lasts = s

i += 1

fact *= i

num *= x

s += num / fact

getcontext().prec -= 2

return +s

print(exp(Decimal(150)))

print(exp(Decimal(400)))

print(exp(Decimal(3000)))

最簡單的調試

最簡單且實用的調試性能調試的方法是使用Linux的time命令,time可以計算程序執行的時間:

time python3 performance.py

1.393709580666379697318341937E+65

5.221469689764143950588763007E+173

7.646200989054704889310727660E+1302

real 0m15.185s

user 0m15.100s

sys 0m0.004s

計算前兩個數的(150,400)很快,而第三個大一點時會很慢,總共要15秒多才算完,是有點卡頓(慢)。

time雖然很便捷有用,但是不能給我們詳細的代碼性能細節。

詳細性能分析cProfile

性能分析另一個常用的方法是使用cProfile,它可以提供很多性能信息

python3 -m cProfile -s time performance.py

例子中,我們使用了cProfile模塊和time參數運行測試腳本,以便按內部時間(cumtime)對行進行排序。如上圖所示,使用cProfile可以給很多內部的具體信息,通過我們可以知道主要耗時是由exp函數導致。知道了程序的性能瓶頸所在,我們就再說明Python性能分析和優化。

優化特定功能

知道了將性能的瓶頸所在(實例中是exp函數),我們為了進一步具體問題具體分析,我們使用一個簡單裝飾器,以便跳過其他代碼,專門分析性能瓶頸所設計的函數。然後使用裝飾器進行測試,具體代碼如下:

def timeit_wrapper(func):

@wraps(func)

def wrapper(*args, **kwargs):

start = time.perf_counter() # Alternatively, you can use time.process_time()

func_return_val = func(*args, **kwargs)

end = time.perf_counter()

print('{0:<10}.{1:<8} : {2:<8}'.format(func.__module__, func.__name__, end - start))

return func_return_val

return wrapper

我們用這個裝飾器來測試exp:

@timeit_wrapper

def exp(x):

...

print('{0:<10} {1:<8} {2:^8}'.format('module', 'function', 'time'))

exp(Decimal(150))

exp(Decimal(400))

exp(Decimal(3000))

結果:

module function time

__main__ .exp : 0.00920036411844194

__main__ .exp : 0.09822067408822477

__main__ .exp : 15.228459489066154

代碼中,我們用到了time包提供time.perf_counter函數,它還提供了另外一個函數time.process_time。兩者的區別在於perf_counter返回的絕對時間,包括Python程序進程未運行時的時間,它可能會受到計算機負載的影響。而process_time僅返回用戶時間(不包括系統時間),這僅是程序過程時間。

性能優化

最後是Python程序的性能優化,為了讓Python程序運行得更快,我們提供一些可供參考的性能優化構想和策略的,通過這些策略我們一半可以提高應用的運行速度,最高情況下可以讓你的應用快30%。

使用內建數據類型

很明顯,內建數據類型非常快,尤其是與自定義類型相比,比如樹或者鍊表。因為內建程序是用C實現的,所以其性能優勢是Python代碼所無法比擬的。

使用lru_cache緩存/記憶

很多時候緩存非常有效,可以極大的提高性能,尤其在數值計算和涉及大量重複調用(遞歸)時。考慮一個例子:

上面的函數使用time.sleep(2)模擬一個耗時的代碼。第一次使用參數1調用時,它將等待2秒,然後返回結果。再次調用時,由於結果已被緩存,將跳過函數的執行,直返回。用3調用時候由於參數不一樣會耗時2秒,總體耗時應該為4s,我們用time 驗證:

real 0m4.061s

user 0m0.040s

sys 0m0.015s

這和我們設想的一致。

使用局部變量

基於變量作用域中查找速度相關,在函數的局部變量具有最高的速度。其次是類級屬性(如self.name)和最慢的是全局變量,如time.time(最慢)。所以我們可以通過避免使用不必要的全局變量來提高性能。

使用函數

這似乎有點出乎意料,因為涉及函數的內存佔用都在堆棧上,而函數返回也會有開銷。但是使用函數,可以避免使用全局變量,可以提高性能。因此,可以通過將整個代碼包裝在main函數中只調用一次來加速代碼。

避免使用屬性

另一個可以是影響程序性能的操作是點運算符訪問對象屬性。點運算符使用__getattribute__觸發會字典查找,會在代碼中產生額外的開銷。我們可以通過一些使用函數而不是類方法的方式避免點操作,比如下面例子

#慢代碼:

import re

def slow_func():

for i in range(10000):

re.findall(regex, line)

#快代碼

from re import findall

def fast_func():

for i in range(10000):

findall(regex, line)

使用f-string

在循環中使用格式符(%s)或.format()時,字符串操作可能會變得非常緩慢。為了進行性能優化,我們應該使用f-string。它是Python 3.6引入的最具可讀性,簡潔性和最快的方法。比如:

s + ' ' + t

' '.join((s, t))

'%s %s' % (s, t)

'{} {}'.format(s, t)

Template('$s $t').substitute(s=s, t=t) # 慢代碼

f'{s} {t}' # 快代碼

總結

性能的調試和優化是非常重要的碼農技術之一。本文中,我們提供了Python應用性能調試和優化的技巧和策略,希望能對大家有所幫助。

相關焦點

  • 【算法系列】凸優化的應用——Python求解優化問題(附代碼)
    :無約束優化問題和約束優化問題,約束優化問題又可分為含等式約束優化問題和含不等式約束優化問題。無約束優化問題含等式約束的優化問題含不等式約束的優化問題針對以上三種情形,各有不同的處理策略:無約束的優化問題:可直接對其求導,並使其為0,這樣便能得到最終的最優解;含等式約束的優化問題:主要通過拉格朗日乘數法將含等式約束的優化問題轉換成為無約束優化問題求解;含有不等式約束的優化問題:主要通過KKT條件(Karush-Kuhn-Tucker Condition
  • 代碼跑得慢甩鍋Python?手把手教你如何給代碼提速30%
    其實某個特定程序(無論使用何種程式語言)的運行速度是快還是慢,在很大程度上取決於編寫該程序的開發人員自身素質,以及他們編寫優化而高效代碼的能力。Medium上一位小哥就詳細講了講如何讓python提速30%,以此證明代碼跑得慢不是python的問題,而是代碼本身的問題。
  • Python 3.8.0來了!
    新版本較3.7版增加了一大波新功能和優化,來新智元 AI 朋友圈與 AI 大咖一起參與討論吧~ 今天,Python 官網宣布,正式發布 Python 3.8.0!
  • 站內優化:代碼優化和標籤優化對網站的重要性
    網站代碼和標籤優化的方法作為一名網站SEO優化人員,對於網站代碼必須要有所了解,這是做網站優化的必備要素之一,網站推廣要想獲得好的績效,原始碼是很關鍵,挑剔的搜尋引擎蜘蛛對於簡潔的網站代碼是情有獨鐘的,這就需要我們對網站代碼進行精簡及優化。
  • 如何在Python中編寫簡單代碼,並且速度超越Spark?
    本文將研究批和實時流(是的,使用簡單Python代碼的實時流)。但開始之前,先進行總體概述。是什麼導致Python既慢又無法擴展?在小型數據集上使用pandas時,其性能表現不錯,但這隻發生在整個數據集適合內存且在pandas和NumPy層下使用已優化的C代碼進行處理的情況下。處理大量數據包含集中的的IO操作、數據轉換、數據拷貝等,拖慢了處理的速度。
  • Python學習第129課——醉漢隨機遊走代碼改進
    【每天幾分鐘,從零入門python編程的世界!】上節我們在Python中用代碼實現了醉漢隨機遊走的邏輯和過程,這節我們把上節的代碼改進一下。現在我們的小例子代碼是非常少的,實際開發中,有些項目代碼量會非常大,為了代碼在執行時有更快的速度,那麼就需要對代碼進行改進優化。
  • 2019年必知的10大頂級Python庫
    在 TensorFlow 創建的所有庫都是用 C 和 C++編寫的,但是,它有一個複雜的前端,是用 python 實現的。你的 python 代碼將被編譯,然後在使用 C 和 C++構建的 TensorFlow 分布式執行引擎上執行。實際上,TensorFlow 的應用是無限的,這就是它美妙的地方。
  • 科悟學院介紹什麼是Python、python能做什麼?
    這是很多人想知道的,今天小編就給你揭秘一個行業——Python(AI人工智慧),有人會問python到底是什麼?能做什麼?下面科悟學院介紹什麼是python和python能做什麼,希望對於正在學習的你有所幫助。
  • 代碼詳解:Python虛擬環境的原理及使用
    · 確保執行Python代碼的腳本使用在給定虛擬環境中安裝的Python解釋器和站點包。最後一點在於會發生一些意想不到的錯誤,稍後會講這一點,但現在先看看在實際中如何實際使用虛擬環境。但丁《神曲·地獄篇》第六章—維吉爾安撫Cerberus插圖:Gustave Doré3.
  • 搭上python號小火箭,程序運行越來越快!
    這一方面和語言有關,另一方面可能就是你代碼的問題。其實,無論使用哪種程式語言,特定程序的運行速度很大程度上都取決於該程序的開發人員及其編寫快而優的程序的技巧和能力。語言方面的問題我們解決不了,所以只能在編程技巧上來提高程序的運行效率。是時候證明給那些python黑粉,讓他們看看如何提升Python程序性能並使其像坐上火箭一樣運行飛快!
  • 乾貨丨Python接口測試自動化實戰及代碼示例:含get、post等方法
    最終選定 python 作為腳本開發語言,使用其自帶的 requests 和 urllib 模塊進行接口請求,使用優化後的 unittest 測試框架編寫測試接口函數,測試結果選用 HTMLTestRunner 框架予以展示,並使用 python 的 ssl 模塊支持 https 協議的驗證。接下來,我詳細地介紹這些模塊,並給出各個模塊完整的測試代碼。
  • 如何在Core i5 上實現 20 倍的 Python 運行速度?
    值得注意的是, 「accelerated Python」 只是使用更快的  Python 算法庫,不需要對代碼做任何改動。當然,我們的 Python 代碼必須使用了某些加速的東西,才能從中獲益。這些優化的核心是對 NumPy 的改變,使得 primitives (在 ndarray 數據上進行運算)能選擇性地使用英特爾 MKL Short Vector Math Library (SVML) 和 MKL Vector Math Library (VML) 的能力。這使得 Python 利用處理器的最新矢量能力,包括多核優化和 AVX/AVX2/AVX-512。
  • 如何在 i5 上實現 20 倍的 Python 運行速度?
    他對外宣布:在配備四核 i5 的 iMAC 上實現了 20 倍的性能加速!至於他是怎麼做到的,請繼續往下看(含代碼)。英特爾團隊表示,他們利用 Xeon Phi,實現過 NumPy 算術和 transcendental 運算在 vector-vector 和 vector-scalar 上最高 400 倍的速度提升。優化 NumPy 和 SciPy 的 FFT這些優化的核心是英特爾 MKL,一系列 NumPy、SciPy 函數都能用到它對 FFT 的原生優化。
  • (提高Java代碼質量)|25個優化Java代碼的小技巧
    1.需要 Map 的主鍵和取值時,應該迭代 entrySet()當循環中只需要 Map 的主鍵時,迭代 keySet() 是正確的。但是,當需要主鍵和取值時,迭代 entrySet() 才是更高效的做法,比先迭代 keySet() 後再去 get 取值性能更佳。
  • 令人讚嘆的8個Python新手工具!
    它的主要功能包括Python shell 窗口(交互式解釋器)、跨平臺(Windows、Linux、UNIX、Mac OS X)、智能縮進、代碼著色、自動提示、可以實現斷點提示、單步執行等調試功能的基本集成調試器。IDLE 易於學習,因為它重量輕且易於使用。但它僅僅是編程世界的敲門磚,可以讓你快速上手,之後的路途依然要找尋一些別的工具。
  • 敲代碼就像寫小說?Jupyter讓文學編程成為現實
    該框架可以在熟悉的Jupyter Notebook環境中編寫代碼,探索和實驗不同的方法,直到找到問題的有效解決方案。然後通過使用某些關鍵詞,nbdev可以將實用功能提取到一個完整的python庫中。確切來說,nbdev通過添加以下支持來補充Jupyter:· 根據最佳實踐,從notebook中自動創建python模塊· 從代碼中自動創建可搜索的超連結文檔· 將pip安裝程序上傳到PyPI· 在標準IDE中編輯和導航代碼· 將所有更改同步回notebook
  • 從系統和代碼實現角度解析TensorFlow的內部實現原理|深度
    1.3 TF代碼目錄組織圖3是TF的代碼結構視圖,下面將簡單介紹TF的目錄組織結構。Tensroflow/python目錄是python API客戶端腳本。Tensorflow/tensorboard目錄是可視化分析工具,不僅可以模型可視化,還可以監控模型參數變化。third_party目錄是TF第三方依賴庫。
  • python基礎課程 第5章 奇妙的內建函數
    當然python語言中還有更多非計算密集型的函數和模塊是基於python語言本身實現的,在這裡我們只需要明白內建函數通常在計算密集型的情況下性能更好即可。關於計算密集型的概念在本文末尾會有一個簡單的解釋(坦白地講,其實現在還有不少 「程式設計師」 對這個概念都模糊不清)。
  • 軟體優化可將CPU性能提升28倍 Intel詳解OneAPI戰略-Intel,優化...
    有很多人不知道,Intel不僅是全球最大的CPU晶片公司,其軟體開發能力也非常強大,軟體工程師就有超過1.5萬人,還是Linux Kernel的最大貢獻者,每年修改的代碼超過50萬行,為100多個作業系統做優化。
  • Python 三十大實踐、建議和技巧
    1、使用 python 3由於官方從2020年1月1日起就停止了對python2.7的更新支持,因此本教程的大部分例子都只能在python 3環境下運行。如果你仍然在使用2.7版本,請先升級到python 3。2、檢查並使用滿足需求的最小python版本你可以在代碼中檢查Python 版本,以確保你的代碼使用者沒有使用不兼容的版本運行腳本。