python 性能優化


1、優化循環

循環之外能做的事不要放在循環內,比如下面的優化可以快一倍

2、使用join合並迭代器中的字符串

join對於累加的方式,有大約5倍的提升

3、使用if is

使用if is Trueif == True將近快一倍

4、使用級聯比較x < y < z

x < y < z效率略高,而且可讀性更好

5、使用**而不是pow

%timeit -n 10000 c = pow(2,20)
%timeit -n 10000 c = 2**20
10000 loops, best of 3: 284 ns per loop
10000 loops, best of 3: 16.9 ns per loop

  **就是快10倍以上!

6、優化包含多個判斷表達式的順序

對於and,應該把滿足條件少的放在前面,對於or,把滿足條件多的放在前面

a = range(2000)  
%timeit -n 100 [i for i in a if 10 < i < 20 or 1000 < i < 2000]
%timeit -n 100 [i for i in a if 1000 < i < 2000 or 100 < i < 20]     
%timeit -n 100 [i for i in a if i % 2 == 0 and i > 1900]
%timeit -n 100 [i for i in a if i > 1900 and i % 2 == 0]
100 loops, best of 3: 287 µs per loop
100 loops, best of 3: 214 µs per loop
100 loops, best of 3: 128 µs per loop
100 loops, best of 3: 56.1 µs per loop

7、使用dict或set查找元素

python dict和set都是使用hash表來實現,查找元素的時間復雜度是O(1)

8、合理使用copy與deepcopy

對於dict和list等數據結構的對象,直接賦值使用的是引用的方式。而有些情況下需要復制整個對象,這時可以使用copy包里的copy和deepcopy,

這兩個函數的不同之處在於后者是遞歸復制的。效率也不一樣:(以下程序在ipython中運行)

import copy
a = range(100000)
%timeit -n 10 copy.copy(a) # 運行10次 copy.copy(a)
%timeit -n 10 copy.deepcopy(a)
10 loops, best of 3: 1.55 ms per loop
10 loops, best of 3: 151 ms per loop


9、使用列表解析和生成器表達式

表解析要比在循環中重新構建一個新的 list 更為高效,因此我們可以利用這一特性來提高運行的效率。

 1 from time import time  
 2  t = time()  
 3  list = ['a','b','is','python','jason','hello','hill','with','phone','test',  
 4  'dfdf','apple','pddf','ind','basic','none','baecr','var','bana','dd','wrd']  
 5  total=[]  
 6  for i in range (1000000):  
 7  for w in list:  
 8  total.append(w)  
 9  print "total run time:" 
10  print time()-t 

使用列表解析:

  1. for i in range (1000000):  
  2. a = [w for w in list] 

上述代碼直接運行大概需要 17s,而改為使用列表解析后 ,運行時間縮短為 9.29s。將近提高了一半。生成器表達式則是在 2.4 中引入的新內容,語法和列表解析類似,但是在大數據量處理時,生成器表達式的優勢較為明顯,它並不創建一個列表,只是返回一個生成器,因此效率較高。在上述例子上中代碼 a = [w for w in list] 修改為 a = (w for w in list),運行時間進一步減少,縮短約為 2.98s。

10、使用xrange代替range

在循環的時候使用 xrange 而不是 range;使用 xrange 可以節省大量的系統內存,因為 xrange() 在序列中每次調用只產生一個整數元素。而 range() 將直接返回完整的元素列表,用於循環時會有不必要的開銷。在 python3 中 xrange 不再存在,里面 range 提供一個可以遍歷任意長度的范圍的 iterator。

11、使用局部變量

使用局部變量,避免”global” 關鍵字。python 訪問局部變量會比全局變量要快得多,因 此可以利用這一特性提升性能

 
        

12、使用is not

if done is not None 比語句 if done != None 更快

13、while 1要比while Trule更快

很多Python優化的文章,都會談及這個。那么,到底能提高多少呢?我們來試試看

 1 import random
 2 import time
 3 
 4 start_time = time.time()  
 5 print start_time  
 6   
 7 j = 1  
 8 while True:  
 9     j += 1  
10     end_time = time.time()  
11     if end_time - start_time >= 1 :  
12         break  
13 print j  
14 print end_time
15 
16 print "======== split =========="
17 start_time = time.time()  
18 print start_time  
19   
20 j = 1  
21 while 1:  
22     j += 1  
23     end_time = time.time()  
24     if end_time - start_time >= 1 :  
25         break  
26 print j  
27 print end_time

輸出結果:

1399342863.16
2573550
1399342864.16
======== split ==========
1399342864.18
2973070
1399342865.18

一個是25萬,一個是29萬。大約提升了16%左右的性能。其實不是很明顯。只是聊勝於無。

14、使用內置函數更快,如add(a,b)要快於a+b

15、如果需要交換兩個變量的值使用 a,b=b,a 而不是借助中間變量 t=a;a=b;b=t;

16、生成序列

用range()函數生成序列,與自定義序列

(1)a = range(0,6)

(2)a = [0, 1, 2, 3, 4, 5]

分別測試了一下,結果如下:

loop_num: 1029877

loop_num: 1602341

結論:還是自己顯式定義序列,效率更高。

17、生成序列副本

 生成一個序列的副本:用copy,與用切片特性

a = [0, 1, 2, 3, 4, 5]

(1)b = copy.copy(a)

(2)b = a[:]

分別測試了一下,結果如下:

loop_num: 677838

loop_num: 1530012

結論:變通的切片應用作為拷貝,比淺拷貝函數效率更高。注意,深拷貝效率很低!

 

18、慎用python內置函數

python內置函數,只是為了應對通用情況。在很多情況下,內置函數的性能,遠遠不如自己寫的,有針對性的函數。動動手,換個算法,就能把性能提高一倍以上。

 

19、選擇合適的格式化字符方式

s1, s2 = 'ax', 'bx' %timeit -n 100000 'abc%s%s' % (s1, s2) %timeit -n 100000 'abc{0}{1}'.format(s1, s2) %timeit -n 100000 'abc' + s1 + s2 100000 loops, best of 3: 183 ns per loop 100000 loops, best of 3: 169 ns per loop 100000 loops, best of 3: 103 ns per loop 

三種情況中,%的方式是最慢的,但是三者的差距並不大(都非常快)。(個人覺得%的可讀性最好)

20、合理使用del

用del可以將對象占用內存空間的引用計數值置零(Deletion of a name removes the binding of that name from the local or global namespace)。它並不能讓對象占用的內存被回收,但一段內存的引用計數變為零,就說明它可以再次被重新使用了(所以del后,不必要GC介入)。

如果不用del,下面這段代碼就可能MemoryError

1 import numpy as np
2 
3 matrix1 = np.zeros((60000,100000))
4 matrix2 = np.zeros((60000,100000))
5 # using matrix1
6 # using matrix2

 

利用del,可以將用完后沒必要占用內存的對象刪掉,下面的代碼對內存耗費就沒上面的大。

1 import numpy as np
2 
3 matrix1 = np.zeros((60000,100000))
4 # using matrix1
5 del matrix1
6 
7 matrix2 = np.zeros((60000,100000))
8 # using matrix2
9 del matrix2

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM