本文經過文章同步功能推送至博客園,顯示排版可能會有所錯誤,請見諒!
生成器能夠理解一種自動實現迭代器協議的數據類型,因此生成器自己就是一個迭代器。 python
區別於列表、元組、字符串等可迭代對象,生成器無需調用__iter__()方法直接就能使用next方法進行迭代。 多線程
生成器有兩種定義方法: 併發
1.定義一個函數。用yield替代return,調用函數時,當運行到yield時,返回一個值同時函數暫停,直到下一次調用函數,返回下一個yield或Stopitertion錯誤。 函數
2.生成器表達式。區別於列表解析式,列表解析式使用[]定義,一經生成,直接讀入內存。而生成器表達式只有在實際調用時纔會讀入內存,使用()定義,優點是內存佔用小,效率高。 高併發
生成器相比於列表解析式,有幾個優勢: 測試
1.佔用內存小,幾乎不佔內存 大數據
2.只有在使用next時,纔會返回值 優化
3.next以前的值都會被python刪除(即佔用內存小的緣由) spa
"""使用列表狀況""" import time t0 = time.time() def make_baozi(n): """製造n個包子並返回""" return ["包子%s" % i for i in range(1,n+1)] def chi_baozi(*args): '''給我多少個包子我就吃多少個''' for i,x in enumerate(args): print('第%d個客人吃了%s' % (i+1,x)) chi_baozi(*make_baozi(5000000))
全程耗時45.34496521949768秒 線程
此時Python佔用內存高達547M且與生產包子數表現出明顯正相關
'''生成器優化''' def make_baozi(n): for i in range(1,n+1): yield '包子%d' %i def chi_baozi(x): print('客人吃了%s' % x) mb = make_baozi(5000000) while True: try: chi_baozi(mb.__next__()) except StopIteration: break
全程耗時47.534424781799316秒
此時Python全程佔用內存6.2M 且內存佔用與生產包子個數不相關
上述代碼爲測試使用列表解析式和生成器表達式的相關佔用區別,能夠看出來,生成器幾乎不佔內存,對於大數據處理內存優化提高十分明顯。在這個模擬程序中,總耗時並沒有顯著區別,主要取決於cpu處理速度。可是對於單個用戶體驗來講,總體有所提高(客人吃到包子1的時間明顯提早了,而吃到最後一個包子時間則相差無幾)。
Python因爲全局鎖(GIT)的存在,其併發效率低一直受人詬病,而Python的多線程和多進程也存在很多問題並不是很好的解決方案,Python開發社區逐漸將視野轉到協程上來,經過多線程/多線程再輔以協程能夠提升併發效率,而協程主要基於生成器來實現。關於生成器與協程,請聽下回分解。