python高性能編程方法一

python高性能編程方法一

 
閱讀 Zen of Python,在Python解析器中輸入 import this. 一個犀利的Python新手可能會注意到"解析"一詞, 認爲Python不過是另外一門腳本...

閱讀 Zen of Python,在Python解析器中輸入 import this. 一個犀利的Python新手可能會注意到"解析"一詞, 認爲Python不過是另外一門腳本語言. "它確定很慢!"php

毫無疑問Python程序沒有編譯型語言高效快速. 甚至Python擁護者們會告訴你Python不適合這些領域. 然而,YouTube已用Python服務於每小時4千萬視頻的請求. 你所要作的就是編寫高效的代碼和須要時使用外部實現(C/C++)代碼. 這裏有一些建議,能夠幫助你成爲一個更好的Python開發者:html

1. 使用內建函數:    你能夠用Python寫出高效的代碼,但很難擊敗內建函數. 經查證. 他們很是快速.2.使用join()鏈接字符串.      你可使用 "+" 來鏈接字符串. 但因爲string在Python中是不可變的,每個"+"操做都會建立一個新的字符串並複製舊內容. 常見用法是使用Python的數組模塊單個的修改字符;當完成的時候,使用 join() 函數建立最終字符串.python

     >>> #This is good to glue a large number of strings算法

     >>> for chunk in input():編程

     >>>    my_string.join(chunk)數組

3. 使用Python多重賦值,交換變量緩存

   這在Python中即優雅又快速:安全

     >>> x, y = y, x服務器

     這樣很慢:數據結構

     >>> temp = x

     >>> x = y

     >>> y = temp          

4. 儘可能使用局部變量

   Python 檢索局部變量比檢索全局變量快. 這意味着,避免 "global" 關鍵字.

5. 儘可能使用 "in"

     使用 "in" 關鍵字. 簡潔而快速.

     >>> for key in sequence:

     >>>     print 「found」

6. 使用延遲加載加速

     將 "import" 聲明移入函數中,僅在須要的時候導入. 換句話說,若是某些模塊不需立刻使用,稍後導入他們. 例如,你沒必要在一開使就導入大量模塊而加速程序啓動. 該技術不能提升總體性能. 但它能夠幫助你更均衡的分配模塊的加載時間.

7. 爲無限循環使用 "while 1"

   有時候在程序中你需一個無限循環.(例如一個監聽套接字的實例) 儘管 "while true" 能完成一樣的事, 但 "while 1" 是單步運算. 這招能提升你的Python性能.

      >>> while 1:

     >>>    #do stuff, faster with while 1

     >>> while True:

     >>>    # do stuff, slower with wile True

8. 使用list comprehension

   從Python 2.0 開始,你可使用 list comprehension 取代大量的 "for" 和 "while" 塊. 使用List comprehension一般更快,Python解析器能在循環中發現它是一個可預測的模式而被優化.額外好處是,list comprehension更具可讀性(函數式編程),並在大多數狀況下,它能夠節省一個額外的計數變量。例如,讓咱們計算1到10之間的偶數個數:

     >>> # the good way to iterate a range

     >>> evens = [ i for i in range(10) if i%2 == 0]

     >>> [0, 2, 4, 6, 8]

     >>> # the following is not so Pythonic

     >>> i = 0

     >>> evens = []

     >>> while i < 10:

     >>>    if i %2 == 0: evens.append(i)

     >>>    i += 1

     >>> [0, 2, 4, 6, 8]

9. 使用xrange()處理長序列:

   這樣可爲你節省大量的系統內存,由於xrange()在序列中每次調用只產生一個整數元素。而相反 range(),它將直接給你一個完整的元素列表,用於循環時會有沒必要要的開銷。

10. 使用 Python generator:

     這也能夠節省內存和提升性能。例如一個視頻流,你能夠一個一個字節塊的發送,而不是整個流。例如,      

     >>> chunk = ( 1000 * i for i in xrange(1000))

     >>> chunk

     <generator object at 0x7f65d90dcaa0>

     >>> chunk.next()

     0

     >>> chunk.next()

     1000

     >>> chunk.next()

     2000

11. 瞭解itertools模塊:

     該模塊對迭代和組合是很是有效的。讓咱們生成一個列表[1,2,3]的全部排列組合,僅需三行Python代碼:

     >>> import itertools

     >>> iter = itertools.permutations([1,2,3])

     >>> list(iter)

     [(1, 2, 3), (1, 3, 2), (2, 1, 3), (2, 3, 1), (3, 1, 2), (3, 2, 1)]

12. 學習bisect模塊保持列表排序:

     這是一個免費的二分查找實現和快速插入有序序列的工具。也就是說,你可使用:

     >>> import bisect

     >>> bisect.insort(list, element)

     你已將一個元素插入列表中, 而你不須要再次調用 sort() 來保持容器的排序, 由於這在長序列中這會很是昂貴.

13. 理解Python列表,其實是一個數組:

     Python中的列表實現並非以人們一般談論的計算機科學中的普通單鏈表實現的。Python中的列表是一個數組。也就是說,你能夠以常量時間O(1) 檢索列表的某個元素,而不須要從頭開始搜索。這有什麼意義呢? Python開發人員使用列表對象insert()時, 需三思. 例如:>>> list.insert(0,item)

     在列表的前面插入一個元素效率不高, 由於列表中的全部後續下標不得不改變. 然而,您可使用list.append()在列表的尾端有效添加元素. 挑先deque,若是你想快速的在兩插入或時。它是快速的,由於在Python中的deque用雙鏈表實現。再也不多說。  

14. 使用dict 和 set 測試成員:      檢查一個元素是在dicitonary或set是否存在 這在Python中很是快的。這是由於dict和set使用哈希表來實現。查找效率能夠達到O(1)。所以,若是您須要常常檢查成員,使用 set 或 dict作爲你的容器.

     >>> mylist = ['a', 'b', 'c'] #Slower, check membership with list:

     >>> ‘c’ in mylist

     >>> True

     >>> myset = set(['a', 'b', 'c']) # Faster, check membership with set:

     >>> ‘c’ in myset:

     >>> True

15. 使用Schwartzian Transform 的 sort():

     原生的list.sort()函數是很是快的。 Python會按天然順序排序列表。有時,你須要非天然順序的排序。例如,你要根據服務器位置排序的IP地址。 Python支持自定義的比較,你可使用list.sort(CMP()),這會比list.sort()慢,由於增長了函數調用的開銷。若是性能有問 題,你能夠申請Guttman-Rosler Transform,基於Schwartzian Transform. 它只對實際的要用的算法有興趣,它的簡要工做原理是,你能夠變換列表,並調用Python內置list.sort() - > 更快,而無需使用list.sort(CMP() )->慢。

16. Python裝飾器緩存結果:

     「@」符號是Python的裝飾語法。它不僅用於追查,鎖或日誌。你能夠裝飾一個Python函數,記住調用結果供後續使用。這種技術被稱爲memoization的。下面是一個例子:

     >>> from functools import wraps

     >>> def memo(f):

     >>>    cache = { }

     >>>    @wraps(f)

     >>>    def  wrap(*arg):

     >>>        if arg not in cache: cache['arg'] = f(*arg)

     >>>        return cache['arg']

     >>>    return wrap

     咱們也能夠對 Fibonacci 函數使用裝飾器:

     >>> @memo

     >>> def fib(i):

     >>>    if i < 2: return 1

     >>>    return fib(i-1) + fib(i-2)

   

    這裏的關鍵思想是:加強函數(裝飾)函數,記住每一個已經計算的Fibonacci值;若是它們在緩存中,就不須要再計算了.

17. 理解Python的GIL(全局解釋器鎖):

     GIL是必要的,由於CPython的內存管理是非線程安全的。你不能簡單地建立多個線程,並但願Python能在多核心的機器上運行得更快。這是由於 GIL將會防止多個原生線程同時執行Python字節碼。換句話說,GIL將序列化您的全部線程。然而,您可使用線程管理多個派生進程加速程序,這些程 序獨立的運行於你的Python代碼外。

18. 像熟悉文檔同樣的熟悉Python源代碼:

     Python有些模塊爲了性能使用C實現。當性能相當重要而官方文檔不足時,能夠自由探索源代碼。你能夠找到底層的數據結構和算法。 Python的源碼庫就是一個很棒的地方:http://svn.python.org/view/python/trunk/Modules

結論:

這些不能替代大腦思考. 打開引擎蓋充分了解是開發者的職責,使得他們不會快速拼湊出一個垃圾設計. 本文的Python建議能夠幫助你得到好的性能. 若是速度還不夠快, Python將須要藉助外力:分析和運行外部代碼.咱們將在本文的第二部分中涉及.  

相關文章
相關標籤/搜索