日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

twisted系列教程十四— pre-fireed deferred

發布時間:2025/3/15 编程问答 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 twisted系列教程十四— pre-fireed deferred 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Introduction

在這一部分我們將要學習deferred 類的另外的一個方面.為了促進討論,我們要為我們的poetry service增加一個server.假設我們有大量的內部的client 想要連接一個相同的外部的server.假設這個server已經很慢而且已經負載很高了.我們不想再讓server上連接更多的client 了.

所以我們會創建一個緩存代理服務器.當一個client 連接到proxy的時候,這個proxy或者從外部的server獲取到一首詩或者就返回一個之前已經緩存了的內容.我們可以讓我們的client 都連接proxy,我們的外部的server 的負載就會很小.我們可以用圖片三十來描述這個過程:


圖片三十

思考一下當一個client連接到proxy 之后會發生什么,假如這個proxy 的緩存是不存在的,這個proxy必須異步等待外部的server 返回一個結果然后才能返回client.到目前為止還不錯,我們已經知道怎樣去處理返回deferred 的異步的函數.另一方面,假如在緩存中已經有了一個一首詩,這個proxy 會把它立即返回,一點也不用等待.所以proxy獲取一首詩的內容可以是同步的或者是異步的.

所以 我們能做些什么假如我們有一個有時異步有時同步的函數?twisted 提供了很多選項,并且它們依據deferred 的一個我們沒有講的特色:你可以在你返回deferred之前觸發它.

這個是管用的,因為盡管你不能觸發一個deferred 兩次,但是你可以在deferred 觸發之后向deferred 中增加callbacks 和 errbacks.當你這樣做的時候,deferred 會繼續的觸發 callback/errback 鏈 從上次它離開的地方.一個很重要的一點是一個已經觸發的deferred 可以立即觸發新假如的callback.

圖片三十一展示了一個已經被觸發的deferred:


圖片三十一

如果我們現在向其中加入一對callback/errback,這個deferred 會立即的觸發新加入的callback,就像圖片三十二:


圖片三十二

我們測試這個deferred 的新特色通過代碼twisted-deferred/defer-11.py.試著運行一下并看看deferred 被觸發之后又加入callback 之后會發生什么.注意在第一個例子中每個新的callback是怎樣被立即觸發的.

第二個例子展示了我們怎樣pause() 一個deferred不讓它立即觸發callback的.當我們都準備好的時候,我們可以用unpause().其實暫停deferred 的原理和 當一個callback 返回deferred 導致外部的deferred 暫停的原理是一樣的.

Proxy 1.0

現在讓我們看一下第一版的poetry proxy –twisted-server-1/poetry-proxy.py,因為這個proxy 同時扮演了client 和 server 的角色,它有兩對 Protocol/Factory.一個用來為poetry 服務,另一個用來從外部的server 獲取詩歌的內容.我們就不看為client 服務的protocol/factory 了,和以前的版本一樣.

讓我們來看 ProxyService,proxy中的server-side protocol 利用它來從外部的server獲取一首詩:

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

重要的方法是get_poem.假如在緩存里已經有一首詩存在,直接返回.如果沒有的話,我們向外部的server 發起一個連接并返回一個deferred,如果等待的詩來到則觸發deferred.get_poem 是一個只有一部分時間是異步的.

怎樣來處理那樣的一個函數呢?讓我們來看一下server-side protocol/factory :

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

這個factory 是很簡單的,它只保存了一個proxy service 的引用,這樣可以讓protocol 實例可以調用get_poem 方法.protocol 是核心所在.它沒有直接的調用get_poem,而是使用了一個twisted.internet.defer 的封裝—maybeDeferred.

maybeDeferred 函數拿到一個函數的引用,并加上了一些參數,maybeDeferred 會最終調用這個函數,并且做如下的工作:

????如果這個函數返回了一個deferred,maybeDeferred 也返回這個deferred,或者
????假如這個函數返回了一個Failure,maybeDeferred 返回一個已經被觸發的deferred ,并帶著failure參數,或者
????假如這個函數返回了一個正常的值,maybeDeferred返回一個已經被觸發的deferred,并帶著這個正常的值作為參數,或者
????假如這個函數拋出了一個錯誤,maybeDeferred會返回一個已經被觸發的deferred,并帶著由這個錯誤轉化來的failure作為參數

?

換句話說,從maybeDeferred 返回的值一定是一個deferred,即使你傳遞過去的函數不會返回deferred.這就讓我們可以安全的調用一個同步的函數,并把它當作一個返回deferred異步的函數.


注意一:這里仍有一點不一樣,被一個同步的函數返回的deferred 是已經被觸發過的,所以任何的你加入的callback 和errback 都會被立即調用,而不是在一些reactor loop 的迭帶之后.
注意二:也許給一個一定會返回deferred 的函數命名為maybeDeferred 不是一個特別好的選擇.

一但這個protocol 有了一個真正的deferred,它可以增加一些callback把詩送到client,并關閉相應的連接.這個就是我們的第一個poetry proxy.

Running the Proxy

要測試我們的代理的話,先開啟一個poetry server,像下面這樣:

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

然后開啟一個proxy server:

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

也就說proxy 運行在10000端口,poetry server 運行在10001端口.
下面你可以運行一個client 連接proxy:

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

我們使用了一個早期的沒有poetry transformations 的client 版本.你可以看到一首詩出現在client 的窗口里,還有一些文字說明它正在從server 下載.如果你再運行client 一次,這個proxy 會告訴你它正在使用緩存起來的poem.

Proxy 2.0

我們前面已經說過,還有另外一種方法可以實現我們的需求.在Porxy 2.0 中有說明,代碼見twisted-server-2/poetry-proxy.py.既然我們可以在返回deferred之前觸發它,我們可以讓proxy service 在緩存中已經存在這首詩的時候返回一個已經觸發過的deferred.下面是proxy service 中get_poem 的新版本:

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

這個defer.succeed 函數是創建一個已經觸發的deferred并返回一個值的很便捷的方法.查看一下它的實現你會發現它就是創建一個deferred ,并用callback()觸發 的封裝.如果我們想返回一個已經失敗了的deferred 我們可以用defer.fail.

在這個版本中,因為get_poem 已經返回了一個deferred,protocol 類不再需要maybeDeferred:

class PoetryProxyProtocol(Protocol):

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

除了這兩個地方的變化之外,其他的沒什么變化了.你可以像上面的方法一樣來運行它.

Summary

在這一部分我們學到了怎樣deferred 在被返回之前被調用,因而我們可以在同步的程序使用它,我們有兩種方法去實現它:

????我們可以使用maybeDeferred來處理時而返回deferred 時而返回正常結果的函數
????我們可以用defer.succed 和 defer.fail 提前觸發我們的deferred,所以我們的有時同步有時異步的函數可以總是返回deferred

?

我們可以使用他們中的任何一個方法.前一個強調了我們的函數不是總是異步的,而后一個讓代碼更簡單.沒有一個定論非要使用哪個.

兩種方法都可以是因為我們可以向deferred中增加callback/errback 在它被觸發之后.它也解了我們在第九部分提出的疑問.我們了解到在deferred中,不管是最后一個callback 或者errback 失敗,錯誤會在deferred 被垃圾回收的時候才被報告出來.現在我們知道因為什么了–因為我們可以一直向一個deferred 對象中增加一個callback/errback 對,直到最后一個對deferred 的引用也消失了,twisted 才能認定這個錯誤沒有被處理.

所以,這就是deferred了嗎?我們已經知道deferred 的全部了嗎? 對于大部分來說,是的.但是twisted 包含了很多我們還沒有探尋到的很多種交替使用deferred 的方式.同時,twisted 的開發人員也在不停的增加新的特色.在將來的發布的版本中,deferred 會有更多的能力.我們會在以后的章節中講到,但首先我們需要從deferred中休息一下,看一些twisted 的其他的方面.

----
20120821 16:08
運行 Proxy 1.0 是做為一個代理服務器,客戶端是連接到這個 Proxy 1.0 上而不是外部的 server 上。如果 Proxy 1.0 中有緩存數據的話,將取到的數據通過 PretryProxyProtocol 中的 d.addCallback(self.transport.write) 發給先前的客戶端。否則向外部的 server 發起一個連接用于取數據,再通過同樣的方式發送給客戶端。

總結

以上是生活随笔為你收集整理的twisted系列教程十四— pre-fireed deferred的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。