在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ Python/ 使用Deferred新功能實現(xiàn)新客戶端
小插曲 Deferred
異步編程模式與Reactor初探
使用Deferred新功能實現(xiàn)新客戶端
由twisted支持的客戶端
增強defer功能的客戶端
改進詩歌下載服務(wù)器
測試詩歌
更加"抽象"的運用Twisted
Deferred用于同步環(huán)境
輪子內(nèi)的輪子: Twisted和Erlang
Twisted 進程守護
構(gòu)造"回調(diào)"的另一種方法
Twisted 理論基礎(chǔ)
惰性不是遲緩: Twisted和Haskell
第二個小插曲,deferred
使用Deferred的詩歌下載客戶端
Deferreds 全貌
結(jié)束
取消之前的意圖
由Twisted扶持的客戶端
改進詩歌下載服務(wù)器
初識Twisted

使用Deferred新功能實現(xiàn)新客戶端

介紹

回憶下第10部分中的客戶端5.1版??蛻舳耸褂靡粋€Deferred來管理所有的回調(diào)鏈,其中包括一個格式轉(zhuǎn)換引擎的調(diào)用。在那個版本中,這個引擎的實現(xiàn)是同步的。

現(xiàn)在我們想實現(xiàn)一個新的客戶端,使用我們在第十二部分實現(xiàn)的服務(wù)器提供的格式轉(zhuǎn)換服務(wù)。但這里有一個問題需要說清楚:由于格式轉(zhuǎn)換服務(wù)是通過網(wǎng)絡(luò)獲取的,因此我們需要使用異步I/O。這也就意味著我們獲取格式轉(zhuǎn)換服務(wù)的API必須是異步實現(xiàn)的。換句話說,try_to_cummingsify回調(diào)將會在新客戶端中返回一個 deferred。

如果在一個deferred的回調(diào)鏈中的一個函數(shù)又返回了一個 deferred會發(fā)生什么現(xiàn)象呢?我們規(guī)定前一個deferred為外層deferred,而后者則為內(nèi)層deferred。假設(shè)回調(diào)N在外層deferred中返回一個內(nèi)層的deferred。意味著這個回調(diào)宣稱“我是一個異步函數(shù),結(jié)果不會立即出現(xiàn)!”。由于外層的deferred需要調(diào)用回調(diào)鏈中下一個callback或errback并將回調(diào)N的結(jié)果傳下去,因此,其必須等待直到內(nèi)層deferred被激活。當(dāng)然了,外層的deferred不可能處于阻塞狀態(tài),因為控制權(quán)此時已經(jīng)轉(zhuǎn)交給了reactor并且阻塞了。

那么外層的deferred如何知曉何時恢復(fù)執(zhí)行呢?很簡單,在內(nèi)層deferred上添加callback或errback即可(即激活內(nèi)層的deferred)。因此,當(dāng)內(nèi)層deferrd被激活時,外層的deferred恢復(fù)其回調(diào)鏈的執(zhí)行。當(dāng)內(nèi)層deferred回調(diào)執(zhí)行成功,那么外層deferred會調(diào)用第N+1個callback回調(diào)。相反,如果內(nèi)層deferred執(zhí)行失敗,那么外層deferred會調(diào)用第N+1個errback回調(diào)。

圖28形象地解釋說明了這一過程:

http://wiki.jikexueyuan.com/project/twisted-intro/images/p13_deferred-111.png" alt="" />

在這個圖示中,外層的deferred有四個callback/errback對。當(dāng)外圍的deferred被激活后,其第一個callback回調(diào)返回了一個deferred(即內(nèi)層deferred)。從這里開始,外層的deferred停止激活其回調(diào)鏈并且將控制權(quán)交還給了reactor(當(dāng)然是在給內(nèi)層deferred添加callback/errback之后)。過了一段時間之后,內(nèi)層deferred被激活,然后執(zhí)行它的回調(diào)鏈并執(zhí)行完畢后恢復(fù)外層deferred的回調(diào)執(zhí)行過程。注意到,外層deferred是無法激活內(nèi)層deferred的。這是不可能的,因為外層的deferred根本就無法獲知內(nèi)層的deferred何時能把結(jié)果準(zhǔn)備好及結(jié)果內(nèi)容是什么。相反,外層的deferred只可能等待(當(dāng)然是異步方式)內(nèi)部deferred的激活。

注意到外層deferred的產(chǎn)生內(nèi)層deferred的回調(diào)的連線是黑色的而不是紅色或藍色,這是因為我們在內(nèi)層deferred激活之前是無法獲知此回調(diào)返回的結(jié)果是執(zhí)行成功還執(zhí)行失敗。只有在內(nèi)層deferred激活時,我們才能決定下一個回調(diào)是callback還是errback。

圖29從reactor的角度來說明了外層與內(nèi)層deferred的執(zhí)行序列:

http://wiki.jikexueyuan.com/project/twisted-intro/images/p13_deferred-12.png" alt="" />

這也許是Deferred類最為復(fù)雜的功能,但無需擔(dān)心你可能會花費大量時間來理解它。我們將在示例twisted-deferred/defer-10.py中說明如何使用它。這個例子中,我們創(chuàng)建了兩個外層deferred,一個使用了簡單的回調(diào),另一個其中的一個回調(diào)返回了一個內(nèi)部deferred。通過閱讀這段代碼,我們可以發(fā)現(xiàn)外層deferred是在內(nèi)層deferred激活后才開始繼續(xù)執(zhí)行回調(diào)鏈的。

客戶端版本6.0

我們將使用新學(xué)的deferred嵌套來重寫我們的客戶端來使用由服務(wù)器提供的樣式轉(zhuǎn)換服務(wù)。其實現(xiàn)代碼在twisted-client-6/get-poetry.py中。與前幾個版本一樣,協(xié)議與工廠都沒有改變。但我們添加了進行格式轉(zhuǎn)換服務(wù)請求的協(xié)議與工廠實現(xiàn)。下面是協(xié)議實現(xiàn)代碼:

class TransformClientProtocol(NetstringReceiver):
    def connectionMade(self):
        self.sendRequest(self.factory.xform_name, self.factory.poem)
    def sendRequest(self, xform_name, poem):
        self.sendString(xform_name + '.' + poem)
    def stringReceived(self, s):
        self.transport.loseConnection()
        self.poemReceived(s)
    def poemReceived(self, poem):
        self.factory.handlePoem(poem)

使用NetstringReceiver作為基類可以很簡單地實現(xiàn)我們的協(xié)議。只要連接一旦建立我們就發(fā)出格式轉(zhuǎn)換服務(wù)的請求。當(dāng)我們得到格式轉(zhuǎn)換之后的詩歌后交給工廠進行處理,下面是工廠代碼:

class TransformClientFactory(ClientFactory):
    protocol = TransformClientProtocol
    def __init__(self, xform_name, poem):
        self.xform_name = xform_name
        self.poem = poem
        self.deferred = defer.Deferred()
    def handlePoem(self, poem):
        d, self.deferred = self.deferred, None
        d.callback(poem)
    def clientConnectionLost(self, _, reason):
        if self.deferred is not None:
            d, self.deferred = self.deferred, None
            d.errback(reason)
    clientConnectionFailed = clientConnectionLost

值得注意的是,工廠是如何處理這兩種類型錯誤:連接失敗和詩歌未全部接收就中斷連接。clientConncetionLost可能會在我們已經(jīng)接收完詩歌后激活執(zhí)行(即連接斷開了),但在這種情況下,self.deferred已經(jīng)是個None值,這得益于handePoem中對deferredr 處理。

這個工廠創(chuàng)建了一個deferred并且最后激活了它,這在Twisted編程中是一個好的習(xí)慣,即

通常情況下,一個對象創(chuàng)建了一個deferred,那么它應(yīng)當(dāng)負責(zé)激活它。

除了格式轉(zhuǎn)換工廠外,還有一個Proxy類包裝了具體創(chuàng)建一個TCP連接到格式轉(zhuǎn)換服務(wù)器:

class TransformProxy(object):
    """
    I proxy requests to a transformation service.
    """
    def __init__(self, host, port):
        self.host = host
        self.port = port
    def xform(self, xform_name, poem):
        factory = TransformClientFactory(xform_name, poem)
        from twisted.internet import reactor
        reactor.connectTCP(self.host, self.port, factory)
        return factory.deferred

這個類提供了一個xform接口,以讓其它程序請求格式轉(zhuǎn)換服務(wù)。這樣一來其它代碼只需要提出請求并得到一個deferred,而無需考慮什么端口與IP地址之類的問題。

剩下的代碼除了try_to_cummingsify外都沒有改變:

def try_to_cummingsify(poem):
    d = proxy.xform('cummingsify', poem)
    def fail(err):
        print >>sys.stderr, 'Cummingsify failed!'
        return poem
    return d.addErrback(fail)

這個作為外層deferred的回調(diào)返回了一個內(nèi)層的deferred,main函數(shù)除了修改創(chuàng)建一個Proxy對象這個地方,其他地方都不需要修改。由于try_to_cummingsify已經(jīng)是deferred回調(diào)鏈中的一部分,因此其早已使用了異步方式, 這里無需更改。

你可能注意到return d.addErrback(fail)這句,其等價于

d.addErrback(fail)
return d

測試客戶端

新版客戶端的啟動和老版的稍微有點不同,如果有1個帶詩歌轉(zhuǎn)換服務(wù)的服務(wù)器運行10001端口,2個詩歌下載服務(wù)器分別運行在10002和10003端口, 你可以這樣啟動客戶端:

python twisted-client-6/get-poetry.py 10001 10002 10003

它會從詩歌下載服務(wù)器下載2首詩歌,然后通過詩歌轉(zhuǎn)換服務(wù)器轉(zhuǎn)換它們。你可以這樣啟動詩歌轉(zhuǎn)換服務(wù)器:

python twisted-server-1/transformedpoetry.py --port 10001

啟動2個詩歌下載服務(wù)器:

python twisted-server-1/fastpoetry.py --port 10002 poetry/fascination.txt
python twisted-server-1/fastpoetry.py --port 10003 poetry/science.txt

現(xiàn)在就可以像上面一樣運行詩歌客戶端了。下面你可以嘗試這樣的場景, 讓詩歌轉(zhuǎn)換服務(wù)器崩掉, 然后用同樣的命令再次運行詩歌客戶端。

結(jié)束語

這一部分我們學(xué)習(xí)了關(guān)于deferred如何透明地在完成了內(nèi)部(deferred)回調(diào)鏈后繼續(xù)處理的過程。并由此,我們可以無需考慮內(nèi)部實現(xiàn)細節(jié)并放心地在外部deferred上添加回調(diào)。

在第十四部分,我們將講解deferred的另外一個特性。

參考

本部分原作參見: dave @ http://krondo.com/?p=2159

本部分翻譯內(nèi)容參見楊曉偉的博客 http://blog.sina.com.cn/s/blog_704b6af70100qay3.html