簡(jiǎn)單介紹Python的Tornado框架中的協(xié)程異步實(shí)現(xiàn)原理
Tornado 4.0 已經(jīng)發(fā)布了很長(zhǎng)一段時(shí)間了, 新版本廣泛的應(yīng)用了協(xié)程(Future)特性. 我們目前已經(jīng)將 Tornado 升級(jí)到最新版本, 而且也大量的使用協(xié)程特性.
很長(zhǎng)時(shí)間沒(méi)有更新博客, 今天就簡(jiǎn)單介紹下 Tornado 協(xié)程實(shí)現(xiàn)原理, Tornado 的協(xié)程是基于 Python 的生成器實(shí)現(xiàn)的, 所以首先來(lái)回顧下生成器.
生成器
Python 的生成器可以保存執(zhí)行狀態(tài) 并在下次調(diào)用的時(shí)候恢復(fù), 通過(guò)在函數(shù)體內(nèi)使用 yield 關(guān)鍵字 來(lái)創(chuàng)建一個(gè)生成器, 通過(guò)內(nèi)置函數(shù) next 或生成器的 next 方法來(lái)恢復(fù)生成器的狀態(tài).
def test(): yield 1
我們調(diào)用 test 函數(shù), 此時(shí)并不會(huì)返回結(jié)果, 而是會(huì)返回一個(gè)生成器
>>> test() <generator object test at 0x100b3b320>
我們調(diào)用其 next 方法則返回 yield 關(guān)鍵字之后的內(nèi)容.
>>> t = test() >>> t.next() 1
如果我們接著調(diào)用 next 方法, 后面又沒(méi)有 yield 關(guān)鍵字繼續(xù)返回的話, 會(huì)拋出一個(gè) StopIteration 異常.
yield 關(guān)鍵字不僅僅能從生成器內(nèi)部返回狀態(tài), 同時(shí)也可以將外部信息傳遞到生成器內(nèi)部, 通過(guò)將 yeild 關(guān)鍵里賦值給變量, 并調(diào)用生成器的 send 方法來(lái)將對(duì)象傳遞到生成器 內(nèi)部. 需要注意的是生成器的開(kāi)始必須調(diào)用其 next 方法, 后面 send 方法調(diào)用的同時(shí) 也會(huì)觸發(fā) next 動(dòng)作. 如果沒(méi)有變量接收 yield 關(guān)鍵字那么 send 傳遞的值將會(huì) 被丟棄.
>>> def test(): a = yield print(a)
首先調(diào)用 next 上面函數(shù)返回的生成器將返回 None, 如果這時(shí)候直接調(diào)用 next 將 會(huì)給生成器發(fā)送 None, 如果調(diào)用 send 發(fā)送一個(gè)值, 將打印這個(gè)值并拋出 StopIteration 異常.
一個(gè)簡(jiǎn)單地協(xié)程
以上就是實(shí)現(xiàn)協(xié)程的所有基礎(chǔ), 為了加深理解, 我們這里寫一個(gè)小例子, 例子我們只使用協(xié)程 開(kāi)啟兩個(gè)甚至多個(gè)死循環(huán), 下面就是一個(gè)極其簡(jiǎn)單地例子::
#!/usr/bin/env python # -*- coding:utf-8 -*-
from __future__ import absolute_import, print_function, division, with_statement def loop1(): """ 循環(huán)1負(fù)責(zé)拋出一個(gè)函數(shù)和對(duì)應(yīng)的參數(shù), 并接收結(jié)果 """ a = 0 ret = 1 while True: ret = yield sum, [a, ret] a, ret = ret, a print("Loop1 ret", ret)
def loop2(): """ 循環(huán)2 負(fù)責(zé)接收函數(shù)并計(jì)算結(jié)果, 然后 yield 出結(jié)果 """ while True: func, args = yield yield func(args) print("Loop2") l1 = loop1() l2 = loop2() tmp = l1.next() for i in range(10): l2.next() ret = l2.send(tmp) tmp = l1.send(ret)
上面例子里 loop1 負(fù)責(zé)產(chǎn)生任務(wù), loop2 負(fù)責(zé)執(zhí)行任務(wù), 主循環(huán)負(fù)責(zé)調(diào)度任務(wù)并將任務(wù)結(jié)果發(fā)回給 任務(wù)產(chǎn)生者.
Tornado 如何做的
我們首先看一個(gè)使用 Tornado 協(xié)程異步的例子
#!/usr/bin/env python # -*- coding:utf-8 -*- from __future__ import absolute_import, print_function, division, with_statement from tornado import gen from tornado import web from tornado import httpclient class ActionHandler(web.RequestHandler): @gen.coroutine def get(self): response = yield httpclient.AsyncHTTPClient().fetch("http://www.linuxzen.com") # ...
其實(shí)原理在上面簡(jiǎn)單地例子里已經(jīng)講清楚了, 我們來(lái)簡(jiǎn)單分析一遍上面的例子, 首先 Tornado 得到 ActionHandler.get 方法拋出(next)的一個(gè)任務(wù), 然后異步的去執(zhí)行任務(wù), 當(dāng)任務(wù)(網(wǎng)絡(luò)請(qǐng)求)結(jié)束或 異常時(shí) Tornado 取得事件通知然后將結(jié)果放回(send)到該方法中讓該方法繼續(xù)執(zhí)行.
由于是異步的, 調(diào)用這個(gè)方法并不會(huì)阻塞其他任務(wù)執(zhí)行.
這時(shí)候我們的方法其實(shí)就是上個(gè)例子 loop1 函數(shù), 而 Tornado 調(diào)度并執(zhí)行了其拋出的任務(wù).
總結(jié)
Tornado 的協(xié)程異步可以讓異步看起來(lái)是順序執(zhí)行的, 可以從一大串的 callback 中解脫出來(lái).
Tornado 的協(xié)程異步并不是這三言兩語(yǔ)能說(shuō)清楚的, 其中有很復(fù)雜的封裝和傳遞, 有興趣可以自己 閱讀源碼.
相關(guān)文章
pandas對(duì)齊運(yùn)算的實(shí)現(xiàn)示例
本文主要介紹了pandas對(duì)齊運(yùn)算的實(shí)現(xiàn)示例,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-10-10python多線程實(shí)現(xiàn)動(dòng)態(tài)圖繪制
這篇文章主要介紹了python多線程實(shí)現(xiàn)動(dòng)態(tài)圖繪制,文章基于Python的相資料展開(kāi)動(dòng)態(tài)圖的繪制相關(guān)內(nèi)容,具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-04-04NumPy-ndarray 的數(shù)據(jù)類型用法說(shuō)明
這篇文章主要介紹了NumPy-ndarray 的數(shù)據(jù)類型用法說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-05-05利用Python實(shí)現(xiàn)無(wú)損GIF動(dòng)圖的制作
這篇文章主要為大家詳細(xì)介紹了如何利用Python實(shí)現(xiàn)無(wú)損GIF動(dòng)圖的制作,文中的實(shí)現(xiàn)方法講解詳細(xì),對(duì)我們學(xué)習(xí)Python有一定的幫助,需要的可以參考一下2023-04-04Python數(shù)據(jù)結(jié)構(gòu)與算法中的隊(duì)列詳解(2)
這篇文章主要為大家詳細(xì)介紹了Python中的隊(duì)列,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助2022-03-03Python隨機(jī)數(shù)用法實(shí)例詳解【基于random模塊】
這篇文章主要介紹了Python隨機(jī)數(shù)用法,結(jié)合實(shí)例形式分析了基于random模塊的各種隨機(jī)數(shù)操作常用技巧,需要的朋友可以參考下2017-04-04python遍歷迭代器自動(dòng)鏈?zhǔn)教幚頂?shù)據(jù)的實(shí)例代碼
迭代器也是用來(lái)遍歷對(duì)象成員的,下面這篇文章主要給大家介紹了關(guān)于python遍歷迭代器自動(dòng)鏈?zhǔn)教幚頂?shù)據(jù)的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-01-01