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

鍍金池/ 教程/ Python/ Deferred用于同步環(huán)境
小插曲 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

Deferred用于同步環(huán)境

介紹

這部分我們要介紹Deferred的另外一個(gè)功能。便于討論,我們?cè)O(shè)定如下情景:假設(shè)由于眾多的內(nèi)部網(wǎng)請(qǐng)求一個(gè)外部詩(shī)歌下載服務(wù)器,但由于這個(gè)外部下載服務(wù)器性能太差或請(qǐng)求負(fù)荷太重。因此,我們不想將所有的內(nèi)部請(qǐng)求全部發(fā)送到外部服務(wù)器。

我們的處理辦法是,在中間添加一個(gè)緩存代理。當(dāng)一個(gè)請(qǐng)求來(lái)到后,緩存服務(wù)器會(huì)從緩存中返回備份(如果有緩存)或者直接從外部服務(wù)器獲得。部署圖如圖30所示:

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

考慮到客戶端端發(fā)送請(qǐng)求來(lái)時(shí),緩存代理可能會(huì)將本地緩沖的詩(shī)歌取出返回,也有可能需要異步等待外部詩(shī)歌下載服務(wù)器的回復(fù)。如此一來(lái),就會(huì)出現(xiàn)這樣的情景:客戶端發(fā)送來(lái)的請(qǐng)求,緩存代理處理請(qǐng)求可能是同步也可能是異步。

要解決這個(gè)需要,就用到了Deferred的另一個(gè)特性:可以在返回Deferred前就激活。之所以可以這樣做,是因?yàn)槟憧梢栽谝粋€(gè)已經(jīng)激活的deferred上添加回調(diào)處理函數(shù)。一個(gè)非常值得注意的是:已經(jīng)被激活的deferred可以立即激活新添加的回調(diào)處理函數(shù)。圖31表示一個(gè)已經(jīng)激活的deferred:

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

如果在此時(shí),我們?cè)贋槠淞硪粚?duì)callback/errback,那么會(huì)立即激活執(zhí)行新的回調(diào)。如圖32

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

后面的callback回調(diào)被執(zhí)行,是因?yàn)榍懊娴腸allback執(zhí)行成功。如果前面執(zhí)行失敗,那么接下來(lái)執(zhí)行的將是新添加的errback回調(diào)。

我們可以通過(guò) twisted-deferred/defer-11.py 示例來(lái)檢測(cè)我們這里說(shuō)到的特性。其中第二組例子,演示了deferred中的pause與unpause函數(shù)的功能,即可以暫停一個(gè)已經(jīng)激活的deferred對(duì)其回調(diào)鏈上回調(diào)的激活。并可以用unpause來(lái)解除暫停設(shè)置。這兩個(gè)函數(shù)同樣完成了在回調(diào)中繼續(xù)產(chǎn)生deferred期間的控制。 我們可以通過(guò) twisted-deferred/defer-11.py 示例來(lái)檢測(cè)我們這里說(shuō)到的特性。其中第二組例子,演示了deferred中的pause與unpause函數(shù)的功能,pause可以暫停一個(gè)已經(jīng)激活的deferred對(duì)其回調(diào)鏈上回調(diào)的激活,unpause可以解除暫停。這個(gè)機(jī)制類(lèi)似于“當(dāng)Deferred回調(diào)鏈上的回調(diào)函數(shù)又返回Deferred時(shí),Deferred暫停自己”。

代理 1.0版本

讓我們來(lái)看看第一個(gè)版本的緩存代理的實(shí)現(xiàn)twisted-server-1/poetry-proxy.py。由于該服務(wù)器既作為服務(wù)器向客戶端請(qǐng)求提供本地緩存的詩(shī)歌,同時(shí)也要作為向外部詩(shī)歌下載服務(wù)器提出下載請(qǐng)求的客戶端,因此其有兩套協(xié)議/工廠,一套實(shí)現(xiàn)服務(wù)器角色,另一套實(shí)現(xiàn)客戶端角色。

首先我們先來(lái)看看ProxyService的實(shí)現(xiàn)部分:

class ProxyService(object):
    poem = None # the cached poem
    def __init__(self, host, port):
        self.host = host
        self.port = port
    def get_poem(self):
        if self.poem is not None:
            print 'Using cached poem.'
            return self.poem
        print 'Fetching poem from server.'
        factory = PoetryClientFactory()
        factory.deferred.addCallback(self.set_poem)
        from twisted.internet import reactor
        reactor.connectTCP(self.host, self.port, factory)
        return factory.deferred
    def set_poem(self, poem):
        self.poem = poem
        return poem

主要的函數(shù)是get_poem。如果緩存中沒(méi)有請(qǐng)求的詩(shī)歌,那么就會(huì)建立連接從外部服務(wù)器中異步取得而返回一個(gè)deferred,并將取得的詩(shī)歌放到緩沖區(qū)中。相反,若緩沖區(qū)中存在請(qǐng)求的詩(shī)歌,則直接返回詩(shī)歌。

我們?nèi)绾蝸?lái)處理這樣一個(gè)返回值不確定的函數(shù)呢,讓我們來(lái)看看實(shí)現(xiàn)服務(wù)器角色的協(xié)議/工廠:

class PoetryProxyProtocol(Protocol):
    def connectionMade(self):
        d = maybeDeferred(self.factory.service.get_poem)
        d.addCallback(self.transport.write)
        d.addBoth(lambda r: self.transport.loseConnection())

class PoetryProxyFactory(ServerFactory):
    protocol = PoetryProxyProtocol
    def __init__(self, service):
        self.service = service

這里使用了maybeDeferred函數(shù)解決了這個(gè)問(wèn)題。此函數(shù)的功能就是如果作為其參數(shù)返回值為defer,那么其不作任何處理,原樣將defer返回。但如何返回值不是defer而是一個(gè)值(正如我們的緩存代理將本地緩沖的詩(shī)歌返回一樣),那么這個(gè)maybeDeferred會(huì)將該值重新打包成一個(gè)已經(jīng)激活的deferred返回,注意是已經(jīng)激活的deferred。當(dāng)然,如果返回的是一個(gè)異常,其也會(huì)將其打包成一個(gè)已經(jīng)激活的deferred,只不過(guò)就不是通過(guò)callback而是errback激活的。

運(yùn)行代理服務(wù)器

啟動(dòng)詩(shī)歌下載服務(wù)器:

python twisted-server-1/fastpoetry.py --port 10001 poetry/fascination.txt

啟動(dòng)代理服務(wù)器:

python twisted-server-1/poetry-proxy.py --port 10000 10001

代理服務(wù)器監(jiān)聽(tīng)10000端口,連接100001端口下載詩(shī)歌。

開(kāi)一個(gè)客戶端:

python twisted-client-4/get-poetry.py 10000

我們使用早期不帶詩(shī)歌翻譯功能的客戶端。你可以看到客戶端窗口中顯示了詩(shī)歌內(nèi)容,代理服務(wù)器窗口顯示“從下載服務(wù)器獲取詩(shī)歌”。你可以再次啟動(dòng)客戶端,代理服務(wù)器會(huì)從緩存中取得詩(shī)歌返回,客戶端顯示的內(nèi)容和剛才一樣。

代理 2.0版本

前面我們已經(jīng)提到,有另一種替代方法來(lái)實(shí)現(xiàn)這一機(jī)制。這在 twisted-server-2/poetry-proxy.py 中很好的說(shuō)明了。即我們可以返回一個(gè)已經(jīng)激活的defer,放在這兒就是如果緩存代理中有請(qǐng)求的詩(shī)歌,那么就通過(guò)返回一個(gè)激活的deferred:

def get_poem(self):
    if self.poem is not None:
        print 'Using cached poem.'
        # return an already-fired deferred
        return succeed(self.poem)
    print 'Fetching poem from server.'
    factory = PoetryClientFactory()
    factory.deferred.addCallback(self.set_poem)
    from twisted.internet import reactor
    reactor.connectTCP(self.host, self.port, factory)
    return factory.deferred

如果我們?nèi)タ?a rel="nofollow" >defer.succeed的源碼會(huì)發(fā)現(xiàn),其只是在返回一個(gè)deferred之前,將其激活。同樣,如果想要返回一個(gè)以失敗的方式激活的deferred,可以調(diào)用函數(shù)defer.fail

在這個(gè)版本中,由于get_poem返回的是deferred而不像前一個(gè)版本存在不確定性因素。因此協(xié)議實(shí)現(xiàn)就無(wú)需使用maybeDeferred(當(dāng)然也可以使用):

class PoetryProxyProtocol(Protocol):
    def connectionMade(self):
        d = self.factory.service.get_poem()
        d.addCallback(self.transport.write)
        d.addBoth(lambda r: self.transport.loseConnection())

除了這兩個(gè)地方,其他地方都是相同的,你可以使用上面的方法運(yùn)行測(cè)試,結(jié)果是一樣的。

總結(jié)

這個(gè)部分我們學(xué)習(xí)到了deferred可以在返回之前被激活,這樣我們就可以將其用于同步環(huán)境中。并且我們已經(jīng)知道了有兩種方法來(lái)實(shí)現(xiàn):

  1. 當(dāng)一個(gè)函數(shù)有時(shí)返回Deferred,有時(shí)返回一個(gè)普通的值,可以使用maybeDeferred函數(shù)
  2. 使用succeed/fail來(lái)返回已經(jīng)激活的Deferred, 包裝“半同步”方法。

兩者返回的都是deferred, 選擇使用哪一種主要看你自己。前面事實(shí)已經(jīng)證明,我們的函數(shù)并不是一直都是異步。如何選擇并沒(méi)有一個(gè)事實(shí)上的標(biāo)準(zhǔn)。

Deferred可以在激活后添加新的回調(diào)也間接說(shuō)明了我們?cè)诘诰挪糠?a rel="nofollow" >twisted-deferred/defer-unhandled.py(提到的,deferred中會(huì)在最后一個(gè)回調(diào)中遇到未處理異常,并在此deferred被垃圾回收(即其已經(jīng)沒(méi)有任何外界引用)時(shí)才將該異常的情況打印出來(lái)。即deferred回在其銷(xiāo)毀前一直持有異常,等待可能還會(huì)添加進(jìn)來(lái)的回調(diào)來(lái)處理。

我們已經(jīng)將deferred中的大部分功能都介紹完了,當(dāng)然Twisted開(kāi)發(fā)人員可能不會(huì)增強(qiáng)deferred的功能。我們下一部分將講講Twisted的其它內(nèi)容。

參考

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

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