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

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

增強(qiáng)defer功能的客戶端

版本5.0

現(xiàn)在我們將要向詩(shī)歌下載客戶端添加一些新的處理邏輯,包括在第九部分提到要添加的功能。不過(guò),首先我要說(shuō)明一點(diǎn):我并不知道如何實(shí)現(xiàn)Byronification引擎。那超出了我的編程能力范圍。取而代之的,我想實(shí)現(xiàn)一個(gè)簡(jiǎn)單的功能,即Cummingsifier。其只是將詩(shī)歌內(nèi)容轉(zhuǎn)換成小寫字母:

def cummingsify(poem)
    return poem.lower()

這個(gè)方法如此之簡(jiǎn)單以至于它永遠(yuǎn)不會(huì)出錯(cuò)。版本5.0的實(shí)現(xiàn)代碼在twisted-client-5/get-poetry.py文件中。我們使用了修改后的 cummingsify,其會(huì)隨機(jī)地選擇以下行為:

  1. 返回詩(shī)歌的小寫版本
  2. 拋出一個(gè)GibberishError異常
  3. 拋出一個(gè)ValueError

這樣,我們便模擬出來(lái)一個(gè)會(huì)因?yàn)楦鞣N意料不到的問(wèn)題而執(zhí)行失敗的復(fù)雜算法。其它部分的僅有的改變?cè)诜椒╬oetry_main中:

def poetry_main():
    addresses = parse_args()
    from twisted.internet import reactor
    poems = []
    errors = []
    def try_to_cummingsify(poem):
        try:
            return cummingsify(poem)
        except GibberishError:
            raise
        except:
            print 'Cummingsify failed!'
            return poem
    def got_poem(poem):
        print poem
        poems.append(poem)
    def poem_failed(err):
        print >>sys.stderr, 'The poem download failed.'
        errors.append(err)
    def poem_done(_):
        if len(poems) + len(errors) == len(addresses):
            reactor.stop()
    for address in addresses:
        host, port = address
        d = get_poetry(host, port)
        d.addCallback(try_to_cummingsify)
        d.addCallbacks(got_poem, poem_failed)
        d.addBoth(poem_done)
    reactor.run()

因此,當(dāng)從服務(wù)器上下載一首詩(shī)歌時(shí),可能會(huì)出現(xiàn)如下情況:

  1. 打印詩(shī)歌的小寫版本
  2. 打印"Cummingsify failed"并附上原始形式的詩(shī)歌
  3. 打印"The poem download failed"。

為了實(shí)現(xiàn)下面內(nèi)容的效果,你可以打開多個(gè)服務(wù)器或打開一個(gè)服務(wù)器多次,直到你觀察到所有不同的結(jié)果,當(dāng)然也嘗試一下去連接一個(gè)沒(méi)有服務(wù)器值守的端口。

圖19是我們給deferred添加回調(diào)后形成的callback/errback鏈:

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

注意到,"pass-throug"errback通過(guò)addCallback添加到鏈中。它會(huì)將任何其接收到的Failure傳遞給下一個(gè)errback(即poem_failed函數(shù))。因此poem_failed函數(shù)可以處理來(lái)自get_poetry與try_to_commingsify兩者的failure。下面讓我們來(lái)分析下deferred可能會(huì)出現(xiàn)的激活情況,圖20說(shuō)明了我們能夠下載到詩(shī)歌并且try_to_commingsify成功執(zhí)行的路線圖:

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

在這種情況中,沒(méi)有回調(diào)執(zhí)行失敗,因此控制權(quán)一直在callback中流動(dòng)。注意到poem_done收到的結(jié)果是None,這是因?yàn)樗](méi)有返回任何值。如果我們想讓后續(xù)的回調(diào)都能觸及到詩(shī)歌內(nèi)容,只要顯式地讓got_poem返回詩(shī)歌即可。

圖21說(shuō)明了我們?cè)诔晒ο螺d到詩(shī)歌后,但在try_to_cummingsify中拋出了GibberishError:

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

由于try_to_cummingsify回調(diào)拋出了GibberishError,所以控制權(quán)轉(zhuǎn)移到了errback鏈,即poem_fail回調(diào)被調(diào)用并傳入的捕獲的異常作為其參數(shù)。

由于poem_failed并沒(méi)有拋出獲異?;蚍祷匾粋€(gè)Failure,因此在它執(zhí)行完后,控制權(quán)又回到了callback鏈中。如果我們想讓poem_fail完全處理好傳進(jìn)來(lái)的錯(cuò)誤,那么返回一個(gè)None是再好不過(guò)的做法了。相反,如果我們只想讓poem_failed采取一部分行動(dòng),但繼續(xù)傳遞這個(gè)錯(cuò)誤,那么我們需要改寫poem_failed,即將參數(shù)err作為返回值返回。如此一來(lái),控制權(quán)交給了下一個(gè)errback回調(diào)。

注意到,迄今為止,got_poem與poem_failed都不可能出現(xiàn)執(zhí)行失敗的情況,因此errback鏈上的poem_done是不可能被激活的。但在任何情況下這樣做都是安全的,這體現(xiàn)了"防御式"編程的思想。比如在got_poem或poem_failed出現(xiàn)了bugs,那么這樣做就不會(huì)讓這些bugs的影響進(jìn)入Twisted的核心代碼區(qū)。鑒于上面的描述,可以看出addBoth類似于try/except中的finally語(yǔ)句。

下面我們?cè)賮?lái)看看第三種可能情況,即成功下載到詩(shī)歌但try_to_cummingsify拋出了VauleError,如圖22:

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

除了got_poem得到是原始式樣的詩(shī)歌而不是小寫版的外,與圖20描述的情況完全相同。當(dāng)然,控制權(quán)還是在try_to_cummingsif中進(jìn)行了轉(zhuǎn)移,即使用了try/except捕獲了ValueError并返回了原始式樣的詩(shī)歌。而這一切deferred并不知曉。

最后,我們來(lái)看看當(dāng)試圖連接一個(gè)無(wú)服務(wù)器值守的端口會(huì)出現(xiàn)什么情況,如圖23所示:

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

由于poem_failed返回了一個(gè)None,因此控權(quán)又回到了callback鏈中。

版本5.1

在版本5.0中我們使用普通的try/except來(lái)捕獲try_to_cummingsify中的異常,而沒(méi)有讓deferred來(lái)捕獲這個(gè)異常。這其實(shí)并沒(méi)有什么錯(cuò)誤,但下面我們將采取一種新的方式來(lái)處理異常。

設(shè)想一下,我們讓deferred來(lái)捕獲 GibberishError 與ValueError 異常,并將其傳遞到errback鏈中進(jìn)行處理。如果要保留原有的行為,那么需要下面的errback來(lái)判斷錯(cuò)誤類型是否為Valuerror,如果是,那么返回原始式樣的詩(shī)歌,這樣一來(lái),控制權(quán)再次回到callback鏈中并將原始式樣的詩(shī)歌打印出來(lái)。

但有一個(gè)問(wèn)題:errback并不會(huì)得到原始詩(shī)歌內(nèi)容 。它只會(huì)得到由cummingsify拋出的vauleError異常。為了讓errback處理這個(gè)錯(cuò)誤,我們需要重新設(shè)計(jì)它來(lái)接收到原始式樣的詩(shī)歌。

一種方法是改變cummingsify以讓異常信息中包含原始式樣的詩(shī)歌。這也正是我們?cè)?.1版本中做的,其代碼實(shí)現(xiàn)在twisted-client-5/get-poetry-1.py中。我們改寫ValueError異常為CannotCummingsify異常,其能將詩(shī)歌作為其第一個(gè)參數(shù)來(lái)傳遞。

如果cummingsify是外部模塊中一個(gè)真實(shí)存在的函數(shù),那么其最好是通過(guò)另一個(gè)函數(shù)來(lái)捕獲非GibberishError并拋出一個(gè)CannotCummingsify異常。這樣,我們的poetry_main就成為:

def poetry_main():
    addresses = parse_args()
    from twisted.internet import reactor
    poems = []
    errors = []
    def cummingsify_failed(err):
        if err.check(CannotCummingsify):
            print 'Cummingsify failed!'
            return err.value.args[0]
        return err
    def got_poem(poem):
        print poem
        poems.append(poem)
    def poem_failed(err):
        print >>sys.stderr, 'The poem download failed.'
        errors.append(err)
    def poem_done(_):
        if len(poems) + len(errors) == len(addresses):
            reactor.stop()
    for address in addresses:
        host, port = address
        d = get_poetry(host, port)
        d.addCallback(cummingsify)
        d.addErrback(cummingsify_failed)
        d.addCallbacks(got_poem, poem_failed)
        d.addBoth(poem_done)

而新的deferred結(jié)構(gòu)如圖24所示:

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

來(lái)看看cummingsify_failed的errback回調(diào):

def cummingsify_failed(err):
    if err.check(CannotCummingsify):
        print 'Cummingsify failed!'
        return err.value.args[0]
    return err

我們使用了Failure中的check方法來(lái)確認(rèn)嵌入在Failure中的異常是否是CannotCummingsify的實(shí)例。如果是,我們返回異常的第一個(gè)參數(shù)(即原始式樣詩(shī)歌)。因此,這樣一來(lái)返回值就不是一個(gè)Failure了,控制權(quán)也就又回到callback鏈中了。否則(即異常不是CannotCummingsify的實(shí)例),我們返回一個(gè)Failure,即將錯(cuò)誤傳遞到下一個(gè)errback中。

圖25說(shuō)明了當(dāng)我們捕獲一個(gè)CannotCummingsify時(shí)的調(diào)用過(guò)程:

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

因此,當(dāng)我們使用deferrd時(shí),可以選擇使用try/except來(lái)捕獲異常,也可以讓deferred來(lái)將異常傳遞到errback回調(diào)鏈中進(jìn)行處理。

總結(jié)

在這個(gè)部分,我們?cè)鰪?qiáng)了客戶端的Deferred的功能,實(shí)現(xiàn)了異常與結(jié)果在callback/errback鏈中"路由"。(你可以將各個(gè)回調(diào)看作成路由器,然后根據(jù)傳入?yún)?shù)的情況來(lái)決定其返回值進(jìn)入下一個(gè)stage的哪條鏈,或者說(shuō)控制權(quán)進(jìn)入下一個(gè)stage的哪個(gè)類型的回調(diào))。雖然示例程序是虛構(gòu)出來(lái)的,但它揭示了控制權(quán)在deferred的回調(diào)鏈中交錯(cuò)傳遞具體方向依賴于返回值的類型。

那我們是不是已經(jīng)對(duì)deferred無(wú)所不知了?不,我們還會(huì)在下面的部分繼續(xù)講解deferred的更多的功能。但在第十一部分,我們先不講這部分內(nèi)容,而是實(shí)現(xiàn)我們的Twisted版本的詩(shī)歌下載服務(wù)器。

參考

本部分原作參見(jiàn): dave @ http://krondo.com/?p=1956

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