首頁  >  文章  >  後端開發  >  實例解析Python的Twisted框架中Deferred物件的用法

實例解析Python的Twisted框架中Deferred物件的用法

高洛峰
高洛峰原創
2017-02-03 16:22:531577瀏覽

Deferred物件結構
Deferred由一系列成對的回呼鏈組成,每一對都包含一個用於處理成功的回呼(callbacks)和一個用於處理錯誤的回呼(errbacks)。初始狀態下,deffereds將由兩個空回調鏈組成。在向其中添加回調時將總是成對添加。當非同步處理中的結果返回時,Deferred將會啟動並以新增時的順序觸發回調鏈。
用實例也許更容易說明,首先來看看addCallback:

from twisted.internet.defer import Deferred
  
def myCallback(result):
  print result
  
d = Deferred()
d.addCallback(myCallback)
d.callback("Triggering callback.")

運行它將會得到如下結果:

Triggering callback.

上例中創建了一個deffered並利用其addCallback方法註冊一個用於處理成功方法註冊一個用於處理成功的回調。 d.callback會啟動deffered並呼叫callback鏈。傳入callback的參數也會被各callback鏈中的第一個函數接收到。
有addCallback,那另一個錯誤的分支,我想也能猜測到了那就是addErrorback,同樣來看個例子:

from twisted.internet.defer import Deferred
  
def myErrback(failure):
  print failure
  
d = Deferred()
d.addErrback(myErrback)
d.errback(ValueError("Triggering errback."))

運行它將會得到如下結果:

[Failure instance: Traceback (failure with no frames): <type &#39;exceptions.ValueError&#39;>: Triggering errback.]

可以看出Twisted會把錯誤封裝在Failure裡。
值得注意的是,在之前提到註冊回呼總是成對的。在使用d.addCallback和d.addErrorback方法時,我們看似只是增加了一個callback或一個errback。而實際上,為了完成這一級回呼鏈的創建,這些方法還會為另一半註冊一個pass-through。要記住,回呼鏈總是具有相同的長度。如果要分別指定這一級回呼的callback和errback。可以使用d.addCallbacks方法:

d = Deferred()
d.addCallbacks(myCallback, myErrback)
d.callback("Triggering callback.")

那麼...今天就先到這裡。

進階範例
接下來就應該來點更為實際的,那就是放進Reactor。先來看一個例子:

from twisted.internet import reactor, defer
  
class HeadlineRetriever(object):
  def processHeadline(self, headline):
    if len(headline) > 50:
      self.d.errback(Exception("The headline ``%s&#39;&#39; is too long!" % (headline,)))
    else:
      self.d.callback(headline)
  
  def _toHTML(self, result):
    return "<h1>%s</h1>" % (result,)
  
  def getHeadline(self, input):
    self.d = defer.Deferred()
    reactor.callLater(1, self.processHeadline, input)
    self.d.addCallback(self._toHTML)
    return self.d
  
def printData(result):
  print result
  reactor.stop()
  
def printError(failure):
  print failure
  reactor.stop()
  
h = HeadlineRetriever()
d = h.getHeadline("Breaking News: Twisted Takes us to the Moon!")
d.addCallbacks(printData, printError)
  
reactor.run()

上例接收一個標題並對其進行處理,如果標題超長會返回超長的錯誤,否則將其轉為HTML並返回。

因所給的標題少於50個字符,故執行以上代碼會得到如下返回:

<h1>Breaking News: Twisted Takes us to the Moon!</h1>

有一點值得注意的,上面用到了reactor的callLater方法,它可以用來做定時事件從而模擬一個異步的請求。

如果我們將標題變得很長,比如說:

h = HeadlineRetriever()
d = h.getHeadline("1234567890"*6)
d.addCallbacks(printData, printError)

那結果是可以遇見的:

[Failure instance: Traceback (failure with no frames): <type &#39;exceptions.Exception&#39;>: The headline ``123456789012345678901234567890123456789012345678901234567890&#39;&#39; is too long!]

我們用圖看一下觸發流程:

Deferredsed會在調用其callback或errback時被觸發;
2. Deferreds僅能被觸發一次!如果嘗試多次觸發將會導致AlreadyCalledError異常;
3. 第N級callback或errback中的Exceptions將會傳入第N+1級的errback中;如果沒有errback,則會拋出Unhandled Error。如果第N級callback或errback中沒有拋出Exception或返回Failure對象,那麼接下來將會由第N+1級中的callback進行處理;
4. callback中傳回的結果將會傳入下一層callback ,並作為其第一個參數;
5. 如果傳入errback的錯誤不是一個Failure對象,那將會被自動包裝一次。

更多實例解析Python的Twisted框架中Deferred物件的用法相關文章請關注PHP中文網!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn