tornado 源碼之 coroutine 分析

tornado 源碼之 coroutine 分析

tornado 的協程原理分析
版本:4.3.0

爲支持異步,tornado 實現了一個協程庫。

tornado 實現的協程框架有下面幾個特點:

  1. 支持 python 2.7,沒有使用 yield from
    特性,純粹使用 yield 實現
  2. 使用拋出異常的方式從協程返回值
  3. 採用 Future 類代理協程(保存協程的執行結果,當攜程執行結束時,調用註冊的回調函數)
  4. 使用 IOLoop 事件循環,當事件發生時在循環中調用註冊的回調,驅動協程向前執行

由此可見,這是 python 協程的一個經典的實現。

本文將實現一個類似 tornado 實現的基礎協程框架,並闡述相應的原理。

外部庫

使用 time 來實現定時器回調的時間計算。
bisect 的 insort 方法維護一個時間有限的定時器隊列。
functools 的 partial 方法綁定函數部分參數。
使用 backports_abc 導入 Generator 來判斷函數是否是生成器。

import time
import bisect
import functools
from backports_abc import Generator as GeneratorType

Future

是一個穿梭於協程和調度器之間的信使。
提供了回調函數註冊(當異步事件完成後,調用註冊的回調)、中間結果保存、結束結果返回等功能

add_done_callback 註冊回調函數,當 Future 被解決時,改回調函數被調用。
set_result 設置最終的狀態,並且調用已註冊的回調函數

協程中的每一個 yield 對應一個協程,相應的對應一個 Future 對象,譬如:

@coroutine
def routine_main():
    yield routine_simple()

    yield sleep(1)

這裏的 routine_simple() 和 sleep(1) 分別對應一個協程,同時有一個 Future 對應。

class Future(object):
    def __init__(self):
        self._done = False
        self._callbacks = []
        self._result = None

    def _set_done(self):
        self._done = True
        for cb in self._callbacks:
            cb(self)
        self._callbacks = None

    def done(self):
        return self._done

    def add_done_callback(self, fn):
        if self._done:
            fn(self)
        else:
            self._callbacks.append(fn)

    def set_result(self, result):
        self._result = result
        self._set_done()

    def result(self):
        return self._result

IOLoop

這裏的 IOLoop 去掉了 tornado 源代碼中 IO 相關部分,只保留了基本需要的功能,如果命名爲 CoroutineLoop 更貼切。

這裏的 IOLoop 提供基本的回調功能。它是一個線程循環,在循環中完成兩件事:

  1. 檢測有沒有註冊的回調並執行
  2. 檢測有沒有到期的定時器回調並執行

程序中註冊的回調事件,最終都會在此處執行。
可以認爲,協程程序本身、協程的驅動程序 都會在此處執行。
協程本身使用 wrapper 包裝,並最後註冊到 IOLoop 的事件回調,所以它的從預激到結束的代碼全部在 IOLoop 回調中執行。
而協程預激後,會把 Runner.run() 函數註冊到 IOLoop 的事件回調,以驅動協程向前運行。

理解這一點對於理解協程的運行原理至關重要。

這就是單線程異步的基本原理。因爲都在一個線程循環中執行,我們可以不用處理多線程需要面對的各種繁瑣的事情。

coroutine

協程返回值

sleep

Runner

因爲沒有使用 yield from,協程無法直接返回值,所以使用拋出異常的方式返回。

copyright

author:bigfish
copyright: 許可協議 知識共享署名-非商業性使用 4.0 國際許可協議

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章