如何理解Tornado中的協程模塊(gen.coroutine)?
如題
智商較差的人表示看不懂知乎上的《怎麼理解coroutine》 ?或者是這個bug(get_doc returns None)的問題出在哪裡?
tornado的coroutine跟greenlet略有區別,跟asyncio里的協程類似。本質上來說只是把本來需要拆成多個callback的代碼合進了一個生成器,生成器不斷yield一系列的Future對象,調度器在Future完成時通過調用生成器的send方法喚醒協程,實現執行-等待-執行-等待的邏輯,而從全局看,所有協程共享一個線程,一個協程等待的時候調度器會插入其他協程進行執行。通過gen修飾的協程本身也會返回一個Future,這個Future在協程返回時完成,等待這個Future就可以達到等待協程執行結束的效果。
本質上什麼是協程?舉個例子:就是類似goto一樣 可以在多個fun之間來回跳轉~ 比如A函數執行到一半然後switch到B函數執行~~諸如此類. 那如果只考慮一個函數呢??那對於A函數而言:其實就是其可以執行到一半先停下,干點別的事情後再接著往下運行~ 看到這裡你是不是想到了debug時的打斷點??執行到斷點的時候就停下,只有next往下setp時候這個函數才接著往下執行~對不對? 那如果我們可以實現類似的斷點機制,是不是就可以實現多個函數來回跳轉呢?A函數執行到斷點時就停下,系統去B執行~等B執行完畢了才回來接著step往斷點後邊的代碼航執行~~~~
協程其實就是這麼個東西,那麼在Python中山門可以實現debug斷點功能呢?當然是yield了~~執行到中間的yield系統就停下返回了~之後在調用next時才回接著往下執行~~~ 你看,是不是通過這個東西就可以做到多個函數之間來回跳轉??!
恩,那山門時候跳轉呢?之前是yield才會,那我是不是可以將之封裝一下呢?封裝成:一個協程,然後sleep就yield出來~~ 折下來就做到協程的功能來~~
tornado協程(coroutine)原理
推薦一篇別人的文章,比較詳細tornado已經通過IO多路復用(multiplexing)實現了請求層面的IO非同步,那麼服務端在收到請求之後,發送響應之前的具體業務代碼里,如何進一步提高性能呢:
(1).tornado.web.asynchronous裝飾器給開發人員提供了將業務代碼非同步化的機會。IOLoop會在任何存在阻塞的時候將線程的執行切換到其他沒有阻塞的業務中。 前提是這些阻塞點必須是IOLoop能識別的, 比如用ioloop自帶的add_timeout方法設置了一個延遲5秒的回調,或者兼容ioloop的第三方驅動(AsyncHTTPClient/torando-redis等等),因為他們都依賴IOLoop的統一調度。【注意:用此裝飾器,要求開發者顯示地調用self.finish()來結束請求】
(2).tornado.gen.coroutine裝飾器通常與 @web.asynchronous結合使用,把非同步的方式由之前採用回調的方式包裝成協程的寫法,而且不用再顯示地調用self.finish()。【福利:Since Tornado 3.1, the combination of @asynchronousand @gen.coroutine has been unnecessary and discouraged; in most cases you should use @gen.coroutine alone.】推薦閱讀:
※知乎為什麼要選擇用Tornado做為web開發框架,非同步非阻塞模式在此起到了作用?
※請問如何處理tornado模板和angular.js的 {{ }} 表達式衝突問題?