如何進(jìn)行 Python 性能優(yōu)化,是本文探討的主要問(wèn)題。本文會(huì)涉及常見(jiàn)的代碼優(yōu)化方法,性能優(yōu)化工具的使用以及如何診斷代碼的性能瓶頸等內(nèi)容,希望可以給 Python 開(kāi)發(fā)人員一定的參考。
Python 代碼優(yōu)化常見(jiàn)技巧
代碼優(yōu)化能夠讓程序運(yùn)行更快,它是在不改變程序運(yùn)行結(jié)果的情況下使得程序的運(yùn)行效率更高,根據(jù) 80/20 原則,實(shí)現(xiàn)程序的重構(gòu)、優(yōu)化、擴(kuò)展以及文檔相關(guān)的事情通常需要消耗 80% 的工作量。優(yōu)化通常包含兩方面的內(nèi)容:減小代碼的體積,提高代碼的運(yùn)行效率。
改進(jìn)算法,選擇合適的數(shù)據(jù)結(jié)構(gòu)
一個(gè)良好的算法能夠?qū)π阅芷鸬疥P(guān)鍵作用,因此性能改進(jìn)的首要點(diǎn)是對(duì)算法的改進(jìn)。在算法的時(shí)間復(fù)雜度排序上依次是:
O(1) -> O(lg n) -> O(n lg n) -> O(n^2) -> O(n^3) -> O(n^k) -> O(k^n) -> O(n!)
因此如果能夠在時(shí)間復(fù)雜度上對(duì)算法進(jìn)行一定的改進(jìn),對(duì)性能的提高不言而喻。但對(duì)具體算法的改進(jìn)不屬于本文討論的范圍,讀者可以自行參考這方面資料。下面的內(nèi)容將集中討論數(shù)據(jù)結(jié)構(gòu)的選擇。
•字典 (dictionary) 與列表 (list)
Python 字典中使用了 hash table,因此查找操作的復(fù)雜度為 O(1),而 list 實(shí)際是個(gè)數(shù)組,在 list 中,查找需要遍歷整個(gè) list,其復(fù)雜度為 O(n),因此對(duì)成員的查找訪問(wèn)等操作字典要比 list 更快。
清單 1. 代碼 dict.py
代碼如下:
from time import time
t = time()
list = ['a','b','is','python','jason','hello','hill','with','phone','test',
'dfdf','apple','pddf','ind','basic','none','baecr','var','bana','dd','wrd']
#list = dict.fromkeys(list,True)
print list
filter = []
for i in range (1000000):
for find in ['is','hat','new','list','old','.']:
if find not in list:
filter.append(find)
print "total run time:"
print time()-t
上述代碼運(yùn)行大概需要 16.09seconds。如果去掉行 #list = dict.fromkeys(list,True) 的注釋,將 list 轉(zhuǎn)換為字典之后再運(yùn)行,時(shí)間大約為 8.375 seconds,效率大概提高了一半。因此在需要多數(shù)據(jù)成員進(jìn)行頻繁的查找或者訪問(wèn)的時(shí)候,使用 dict 而不是 list 是一個(gè)較好的選擇。
•集合 (set) 與列表 (list)
set 的 union, intersection,difference 操作要比 list 的迭代要快。因此如果涉及到求 list 交集,并集或者差的問(wèn)題可以轉(zhuǎn)換為 set 來(lái)操作。
清單 2. 求 list 的交集:
代碼如下:
from time import time
t = time()
lista=[1,2,3,4,5,6,7,8,9,13,34,53,42,44]
listb=[2,4,6,9,23]
intersection=[]
for i in range (1000000):
for a in lista:
for b in listb:
if a == b:
intersection.append(a)
print "total run time:"
print time()-t
上述程序的運(yùn)行時(shí)間大概為:
total run time:
38.4070000648
清單 3. 使用 set 求交集
代碼如下: