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

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

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

介紹

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

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

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

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

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

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

如果在此時,我們再為其另一對callback/errback,那么會立即激活執(zhí)行新的回調(diào)。如圖32

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

后面的callback回調(diào)被執(zhí)行,是因為前面的callback執(zhí)行成功。如果前面執(zhí)行失敗,那么接下來執(zhí)行的將是新添加的errback回調(diào)。

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

代理 1.0版本

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

首先我們先來看看ProxyService的實現(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。如果緩存中沒有請求的詩歌,那么就會建立連接從外部服務(wù)器中異步取得而返回一個deferred,并將取得的詩歌放到緩沖區(qū)中。相反,若緩沖區(qū)中存在請求的詩歌,則直接返回詩歌。

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

運行代理服務(wù)器

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

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

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

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

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

開一個客戶端:

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

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

代理 2.0版本

前面我們已經(jīng)提到,有另一種替代方法來實現(xiàn)這一機制。這在 twisted-server-2/poetry-proxy.py 中很好的說明了。即我們可以返回一個已經(jīng)激活的defer,放在這兒就是如果緩存代理中有請求的詩歌,那么就通過返回一個激活的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的源碼會發(fā)現(xiàn),其只是在返回一個deferred之前,將其激活。同樣,如果想要返回一個以失敗的方式激活的deferred,可以調(diào)用函數(shù)defer.fail

在這個版本中,由于get_poem返回的是deferred而不像前一個版本存在不確定性因素。因此協(xié)議實現(xiàn)就無需使用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())

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

總結(jié)

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

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

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

Deferred可以在激活后添加新的回調(diào)也間接說明了我們在第九部分twisted-deferred/defer-unhandled.py(提到的,deferred中會在最后一個回調(diào)中遇到未處理異常,并在此deferred被垃圾回收(即其已經(jīng)沒有任何外界引用)時才將該異常的情況打印出來。即deferred回在其銷毀前一直持有異常,等待可能還會添加進(jìn)來的回調(diào)來處理。

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

參考

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

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