天天看點

Tornado 源碼分析(一)

tornado.gen.engine 是 tornado v3.0.0之前用于異步方法的。 具體點說如果一個方法内部使用yield 方法傳回一個異步調用的結果, 那麼這個方法必須使用tornado.gen.engine裝飾。 tornado v3.0.0之後被tornado.gen.coroutines取代。

如果沒有engine, 異步也是可行的,隻不過需要大量callback, 就像javascript那樣。

一個最經典的異步handler如下:

<code>@asynchronous</code> 用來說明這個get方法是異步的, tornado 不在負責finish request, 由handler自己處理。

<code>tornado.httpclient.asynchttpclient.fetch</code> 是進行異步網路請求的方法。其函數聲明為:

<code>def fetch(self, request, callback, **kwargs)</code>

可見他有一個callback參數, 當網絡請求完成後, 将調用callback方法, 這一切是有ioloop實作的。

使用engine後,代碼會更接近順序代碼,沒有回調如下:

但是在<code>asyncdemo</code> 的例子中, <code>tornado.httpclient.asynchttpclient.fetch</code> 放到了task中, 當異步方法完成時, response被直接指派給了response 。 callback還是存在的, 也是執行的,隻不過task和engine 這兩個東西,讓代碼接近順序代碼了。

原理是這樣的:

函數内部如果有yield, 那麼調用這個函數講産生types.generator執行個體, 這個函數的調用将由這個生成器控制。

運作結果如下:

tornado.gen.runner是一個管理生成器和生成器内部異步函數運作結果的類。被engine裝飾的函數, 每當調用都會産生一個生成器,同時tornado都會為他生成一個runner執行個體,runner執行個體負責在合适的時候調用這個生成器的send方法,把函數執行完。

runner在什麼時候調用生成器的send方法呢? 這是由回調函數決定的。當回調函數執行時, 我們有了異步函數的執行結果response, 同時有了函數運作體runner, 由runner負責send(response)。 這樣我們的函數就能向下運作了。 是以需要将runner和callback關聯。 tornao.gen.task完成了這項任務。

注意start方法, 首先向runner注冊了一個key, 在runner内部, func的回調結果會和這個key關聯。

然後構造了一個callback函數, runner.result_callback源碼如下:

可見,當回調函數運作時, runner記錄了異步函數的回調結果,并和key關聯,然後觸發了runner繼續往後運作。

runner.run 方法也就很好了解了

原文出處: http://shaolianbo.github.io/web/tornado/2015/03/01/tornado1