gevent簡介

gevent是基於協程的Python網絡庫。linux

協程存在的意義:對於多線程應用,CPU經過切片的方式來切換線程間的執行,線程切換時須要耗時(保存狀態,下次繼續)。協程,則只使用一個線程,在一個線程中規定某個代碼塊執行順序,當程序中存在大量不須要CPU的操做時(IO),適用於協程。編程

特色:基於libev的快速事件循環(Linux上epoll,FreeBSD上kqueue),基於greenlet的輕量級執行單元。並且其中有個monkey類,將現有基於Python線程直接轉化爲greenlet(相似於打patch)。windows

libev:libev是libevent以後的一個事件驅動的編程框架,其接口和libevent基本相似。據官方介紹,其性能比libevent還要高,bug比libevent還少。Libev經過一個structev_loop結構表示一個事件驅動的框架。在這個框架裏面經過ev_xxx結構,ev_init、ev_xxx_set、ev_xxx_start接口向這個事件驅動的框架裏面註冊事件監控器,當相應的事件監控器的事件出現時,便會觸發該事件監控器的處理邏輯,去處理該事件。處理完以後,這些監控器進入到下一輪的監控中。而libevent是一個事件觸發的網絡庫,適用於windows、linux、bsd等多種平臺,內部使用select、epoll、kqueue、IOCP等系統調用管理事件機制,libevent支持用戶使用三種類型的事件,分別是網絡IO、定時器、信號三種,Libev 除了提供了基本的三大類事件(IO事件、定時器事件、信號事件)外還提供了週期事件、子進程事件、文件狀態改變事件等多個事件,libevent支持多線程編程,每一個事件須要關聯到本身的event_base。網絡

greenlet:指的是使用一個任務調度器和一些生成器或者協程實現協做式用戶空間多線程的一種僞併發機制,即所謂的微線程。主要思想是:生成器函數或者協程函數中的yield語句掛起函數的執行,直到稍後使用next()或send()操做進行恢復爲止。可使用一個調度器循環在一組生成器函數之間協做多個任務。greenlet不是一種真正的併發機制,而是在同一線程內,在不一樣函數的執行代碼塊之間切換,實施「你運行一會、我運行一會」,而且在進行切換時必須指定什麼時候切換以及切換到哪,所以,greenlet本質是一種合理安排了的串行。多線程

monkey patch:在最開頭的地方gevent.monkey.patch_all();把標準庫中的thread/socket等給替換掉.這樣咱們在後面使用socket的時候能夠跟日常同樣使用,無需修改任何代碼,若是不進行 monkey patch,會形成嚴重後果,性能降低,數據錯誤,代碼切換異常等。併發

要想理解gevent首先要理解gevent的調度流程,gevent中有一個hub的概念,也就是MainThread,用於調度全部其它的greenlet實例。框架

 

每次從hub切換到一個greenlet後,都會回到hub,這就是gevent的關鍵,gevent中並無greenlet鏈的說法,全部都是向主循環註冊greenlet.switch方法,主循環在合適的時機切換回來。爲何每次都要切換到hub呢?socket

1.hub是事件驅動的核心,每次切換到hub後將繼續循環事件。若是在一個greenlet中不出來,那麼其它greenlet將得不到調用。函數

2.維持二者關係確定比維持多個關係簡單。每次咱們所關心的就是hub以及當前greenlet,不須要考慮各個greenlet之間關係。oop

下面看一個簡單的gevent的例子:

 

 

咱們對這段小代碼進行debug,而後在控制檯查看線程數:

 

 

只有一個線程,他run的實際上是greenlet這個僞線程。

 

 

而後看執行結果:

 

 

咱們用顯式的sleep使其進行切換,能夠看到在sleep後,代碼切換到了其餘greenlet,由於gevent認爲此處出現了阻塞,一旦檢測到阻塞,gevent就會自動進行greenlet切換。若是不進行顯式調用,則greenlet實際上是順序執行的,由於本質上它是串行的,如今咱們將sleep去掉,結果是這樣:

 

 

實際代碼裏,咱們不會用gevent.sleep()去切換協程,而是在執行到IO操做時,gevent自動切換,代碼以下:

 

 

咱們沒有顯式的進行sleep,而是依賴各個IO操做自身的阻塞時間,下面咱們看下結果:

 

 

能夠看到,結束順序和IO發起順序並不一致。gevent.spawn()方法建立greenlet實例並調用其start方法發起,而後經過gevent.joinall將greenlet實例加入到greenlet執行隊列中等待其完成,這裏能夠爲其設置超時時間。

gevent還能夠做爲起celery worker和celery beat時的POOL(支持prefork (default), eventlet, gevent, solo or threads),在啓動celery worker時,-P爲gevent,即指定gevent爲POOL。

相關文章
相關標籤/搜索