協程模塊gevent

更新:導入一個有monkey.patch_all()的庫,應該用函數把它包起來,否則會拋出錯誤python

- RuntimeError: cannot release un-acquired lock 編程

 

在《python高性能編程》一書中做者開始講協程用的就是gevent模塊做爲例子。先舉一個簡單的例子:函數

協程極大大提升了性能

若是有100個foo,bar函數,每一個須要阻塞一秒,那麼串行執行須要100秒以上,而I/O多路複用執行,在一秒以後100個程序執行完畢。性能

協程提升性能的緣由ui

  - 全部的阻塞請求同時發生,只要函數輸入到位
    -  cpu和操做系統的高度配合
spa

    -能夠這麼想象   操作系統

     1  線程讀代碼,讀到一步須要去取數據,
     2  線程本身不取數據,叫操做系統去取,取數據步驟參考途中1,3,4,2
     3  操做系統取數據,線程就不讀代碼了,不幹其餘事,就在這等着
     4 等數據到了,線程繼續讀代碼,按代碼幹事
線程

 -重點來了,IO多路複用以後事情發生了變化:協程

   - 線程很快找到查看了代碼,發現代碼中指出了有一些代碼是能夠同時執行的
   - 好比下圖有4處能夠同時執行的代碼,
對象

    -每一處代碼裏面可能也有阻塞,因爲更裏面的阻塞還不能發起請求主要先不關注,

    - 線程拿起1處的代碼,向系統發起請求,不等待,回到代碼2處

    - 再去操做系統處發送請求,如此反覆,直到代碼代表的特殊代碼塊都發起了請求
   - 線程毫無停歇,只要操做系統使其獲得數據,他就運行代碼,並重復以上步驟 
   - 對比:在串行的狀況下,線程在1.1處停下等待0.1s,而IO多路複用已經把活全作完了

 


協程做用的範圍:
 -   如下兩個條件同時具有

         I/O密集型任務。
               任務自己結果不受其餘任務
 

如何標記特殊代碼塊。(猴子補丁+gevent.spawn())

  - 打上猴子補丁

    from gevent import monkey
    monkey.patch_all()

  - gevent.spawn(function,*arg,**kwargs) 

    若是一個function內部沒有阻塞,那麼到這一步,正常執行
    若是function能有阻塞,那麼它被凍結並被標記成特殊代碼塊
  - 使用內置方法使其開始執行

    gevent.joinall()生成對象是list類型

         iwait生成對象是生成器類型

    對單個對象使用.join()方法,可是沒法經過.value獲取函數返回值

    對單個對象使用.get()方法,能夠直接運行並得到返回值,get(timeout=3)還能設置超時時間
        - 無論哪一個方法,生成對象的元素使用.value,獲得那些特殊代碼塊的返回值,

    若是沒有返回值,那就不用管

信號量(from gevent.lock import BoundedSemaphore)

   -  生成計算器對象,並設置值

    bigest=BoundedSemaphore(5)

      生成最大數爲5的計數器

   - 在代碼中調用

    使用with方法

    或使用bigest.acquire(), bigest.release()

只能用一次的超時控制(gevent.Timeout):

  - 在.join()方法前加上
     timeout=Timeout(2)

     timeout.start() 

  - timeout支持with調用,其__enter__()方法調用了start(),不知道在函數內部調用會有什麼效果?

還有許多內容,但用好上面這些已能讓你代碼執行速度快上十倍了。

 

好吧,再來一點乾貨:不一樣線程內相互控制以及傳遞值

   import gevent from gevent.event import AsyncResult

  a = AsyncResult()

  a.set('值')
  a.get()='值'

  解釋:a實例化時給全部a.get() 後面的代碼加鎖,而後a.set()解鎖,a.get()獲取一個值 

相關文章
相關標籤/搜索