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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

twisted系列教程七–小插曲,延迟对象

發布時間:2025/3/15 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 twisted系列教程七–小插曲,延迟对象 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

在第六部分,我們得出這樣一個結論:callbacks 是twisted異步編程的一個重要組成部分.callback 是交織在twisted結構中的,而不僅僅是連接reactor 的一種方法.所以用twisted 或者其他的基于reactor 的異步程序,就意味著把我們的程序組織成被reator觸發的callback鏈.
甚至像我們的簡單的get_poetry方法都需要兩個callback,一個用來處理正常的返回結果,另一個用來處理錯誤.作為一個twisted 的程序員,我們將來會大量的用到它們.我們應該花費點時間想想使用callback 的最好的方法,還有我們將會遇到那些陷阱.

看一下下面的一段代碼,在client 3.1 版本中:

def got_poem(poem):
????print poem
????reactor.stop()

def poem_failed(err):
????print >>sys.stderr, 'poem download failed'
????print >>sys.stderr, 'I am terribly sorry'
????print >>sys.stderr, 'try again later?'
????reactor.stop()

get_poetry(host, port, got_poem, poem_failed)

reactor.run()

完成的功能很簡單:

????如果得到了詩,打印出來
????如果沒有得到詩,打印一個錯誤
????在上面兩種情況之后,結束程序

如果是同步的類似的程序應該像下面這樣:

try:
????poem = get_poetry(host, port)
???# the synchronous version of get_poetry
except Exception, err:
????print >>sys.stderr, 'poem download failed'
????print >>sys.stderr, 'I am terribly sorry'
????print >>sys.stderr, 'try again later?'
????sys.exit()
else:
????print poem
????sys.exit()

callback 就像 else 代碼塊,而errback 就像except 代碼塊.也就意味著,異步程序的觸發errback就像拋出一個異常而觸發callback就像走正常的程序流.

這兩個版本代碼之間的不同之處是什么?在同步的版本中,python 的解釋器會保證只要get_poetry 拋出任何異常,except塊就會運行.如果我們能相信python解釋器能正確運行代碼,我就能相信出錯處理部分的代碼能運行.

和異步程序相比:poem_failed errback 會被我們的代碼觸發–PoetryClientFactory中的clientConnectionFailed,是我們而不是python 在控制出錯假如出錯的話,所以我們要確保要去處理每一個會出錯的情況,并觸發相應的errback.否則的話我們的程序將會等待一個永遠不會來的callback然后卡在那里.

這個是同步程序和異步程序的令一個區別.在同步程序中,如果我們不去捕捉出現的異常,python 解釋器會幫我們捕捉它然后程序崩潰掉并告訴我們出現了什么錯誤.但是假如我們忘記拋出一個異步的錯誤,我們的程序就會不停停止,過起了什么也不直到的性福生活.

很明顯的,在異步程序中處理異常是很重要的,也是很棘手的.在異步程序中出錯處理比處理正常的結果更重要,因為事情出錯的方法遠比正常運行的方法多.在用twisted過程中,忘記處理錯誤是一經常犯的錯誤.

對上面的額同步程序來說:else 代碼塊和except 代碼塊都會只運行一次,python 解釋器并不會忽然的決定要運行它們兩個,或者一時高興,運行了else 代碼塊27次.

但是在異步程序中,callback 和errback 都是由我們來控制的,我們可能會犯錯.我們可能既調用了callback 也調用了errback,或者調用了callback 27次.然后調用我們寫的get_poetry 的那個娃可就要悲劇了. 雖然twisted 中沒有明確說,但就像同步程序中的try/except 一樣,在twisted 中,我們要調用callback 一次 或者調用errback 一次.運行get_poetry一次,我們或者得到詩歌或者沒有得到.

試著想一下如果你去調試一個發起了三個poetry請求并調用了七個callback 和兩個errback 的程序, 你可以從哪里下手呢? 你可能會結束你的callbacks 和errbacks 然后去監測在一個get_poetry請求中他們什么時候被觸發了兩次.

還有一點就是:兩個版本的get_poetry都有一些重復的代碼.異步的版本調用了兩次reactor.stop同步的版本調用了兩次sys.exit.我們可以把同步版本的重構成這樣:

...
try:
????poem = get_poetry(host, port) # the synchronous version of get_poetry
except Exception, err:
????print >>sys.stderr, 'poem download failed'
????print >>sys.stderr, 'I am terribly sorry'
????print >>sys.stderr, 'try again later?'
else:
????print poem

sys.exit()

異步的版本可以重構嗎?我們對此還不太確定,因為我們異步的get_poetry callback 和errback是兩個不同的函數,難道你想讓我們把它簡化成一個callback?

ok,下面是我們對使用callback進行編程的一些看法:

????調用errback 非常重要.因為errback就是except語句,用戶需要依賴它們,它們不是可選的
????不要在錯誤的時間觸發callback和在正確的時間觸發它們一樣重要,callback 和errback 是互赤,只能運行一個
????在使用callback的時候,代碼是不容易重構的


我們在將來的章節仍會講callbacks,但現在我們要去看有沒有一個抽象可以很好的管理callbacks.

The Deferred

callback在異步程序中使用的非常多,但就我們發現如果要正確的使用它們是很困難的.twisted 的開發者們創造了一個叫做Deferred 的抽象可以幫助我們來處理callbacks.Deferred 類在twisted.internet.defer中定義.

一個deferred 一對callback 鏈,一個是用來處理正確結果的,另一個是用來處理出錯結果的.一個新的deferred 含有兩個空的鏈.我們可以通過增加callbacks 和 errbacks 來填充這兩條鏈,然后用一個正常的結果或者異常來觸發deferred.觸發deferred 會按照callback或errback被加入進去的順序調用它們.圖片十二描述了帶有callback/errback 鏈的deferred 實例.


圖片十二

讓我們測試一下,因為deferred 沒有用到reactor,我們不用開啟一個循環,我們的第一個deferred 的例子是 twisted-deferred/defer-1.py:

from twisted.internet.defer import Deferred

def got_poem(res):
????print 'Your poem is served:'
????print res

def poem_failed(err):
????print 'No poetry for you.'

d = Deferred()

# add a callback/errback pair to the chain
d.addCallbacks(got_poem, poem_failed)

# fire the chain with a normal result
d.callback('This poem is short.')

print "Finished"

這段代碼新建了一個新的deferred,然后用addCallbacks加入了一對callback/errback.然后callback觸發了正常結果的callback.當然這里并沒有一個callback 鏈,只有一個callback.但不管怎么樣,運行這個代碼然后輸出如下:

Your poem is served:
This poem is short.
Finished

非常簡單,下面是需要注意的一些東西:

????就像在client 3.1我們用的callback/errback,我們向deferred 中加入的callback一次接收一個參數,或者一個正常的結果或者一個錯誤的結果.實際上deferred支持callback和errback帶有多個參數,但是最少一個.但第一個參數永遠是callback 或者errback
????我們增加callbacks和errbacks的時候是一對對的
????callback方法用一個正常的結果觸發deferred
????看一下輸出的順序,我們可以看到觸發defferred之后立即調用了callback.這里根本沒有異步,因為沒有用reactor.


讓我們看另一個例子在twisted-deferred/defer-2.py,這次觸發deferred 的errback:

from twisted.internet.defer import Deferred
from twisted.python.failure import Failure

def got_poem(res):
????print 'Your poem is served:'
????print res

def poem_failed(err):
????print 'No poetry for you.'

d = Deferred()

# add a callback/errback pair to the chain
d.addCallbacks(got_poem, poem_failed)

# fire the chain with an error result
d.errback(Failure(Exception('I have failed.')))

print "Finished"

在我們運行之后有如下輸出:

No poetry for you.
Finished

所以要觸發errback 鏈只要調用errback方法 就可以了,這個方法參數是一個錯誤的返回結果.就像之前的callback一樣,errback在觸發之后立即被調用了.

在上一個例子中,我們傳遞一個Failure對象給errback,這樣沒什么問題.但是deferred 會自動把普通的Exception 轉變為Failures對象,我們在twisted-deferred/defer-3.py可以看到:

from twisted.internet.defer import Deferred

def got_poem(res):
????print 'Your poem is served:'
????print res

def poem_failed(err):
????print err.__class__
????print err
????print 'No poetry for you.'

d = Deferred()

# add a callback/errback pair to the chain
d.addCallbacks(got_poem, poem_failed)

# fire the chain with an error result
d.errback(Exception('I have failed.'))

在這里我們傳遞給errback 一個正常的Exception.我們得到如下的輸出:


twisted.python.failure.Failure
[Failure instance: Traceback (failure with no frames): : I have failed.
]
No poetry for you.

這就意味著當我們用deferred 的時候,我們可以用正常的Exception,deferred 會自動的為我們轉為Failure對象.defferred 會保證每一個errback被觸發的時候都會被傳入一個Failure 實例.

我嘗試著按了callback 的按鈕也嘗試著按了errback 的按鈕.就像任何一個好的工程師一樣,你可能想要一遍一遍的按它們.為了讓代碼更短一些,我們讓callback和errback 都是同一個函數.記住它們返回的內容不同,一個是正常的結果,一個是錯誤.代碼在這里twisted-deferred/defer-4.py:

from twisted.internet.defer import Deferred
def out(s): print s
d = Deferred()
d.addCallbacks(out, out)
d.callback('First result')
d.callback('Second result')
print 'Finished'

你會得到如下的輸出:

First result
Traceback (most recent call last):
...
twisted.internet.defer.AlreadyCalledError

灰常有意思,defferred 不會讓我們多次觸發正常的callback.實際上,不管如何defferred 都不讓人觸發兩次,下面的例子會證明這一點:

????twisted-deferred/defer-4.py
????twisted-deferred/defer-5.py
????twisted-deferred/defer-6.py
????twisted-deferred/defer-7.py


注意最后的print 語句都沒有運行到. 當我們用defferred來管理我們的callbacks 的時候,我們就不會范既調用callback 又調用errback 的錯誤.我們可以試一下,但是deferred會拋出異常來提醒我們.

deferred 可以幫助我們重構異步的代碼嗎?讓我們看一下例子twisted-deferred/defer-8.py:

import sys

from twisted.internet.defer import Deferred

def got_poem(poem):
????print poem
????from twisted.internet import reactor
????reactor.stop()

def poem_failed(err):
????print >>sys.stderr, 'poem download failed'
????print >>sys.stderr, 'I am terribly sorry'
????print >>sys.stderr, 'try again later?'
????from twisted.internet import reactor
????reactor.stop()

d = Deferred()

d.addCallbacks(got_poem, poem_failed)

from twisted.internet import reactor

reactor.callWhenRunning(d.callback, 'Another short poem.')

reactor.run()

這個是我們原始的代碼.注意我們在啟動reactor之后,用callWhenRunning來觸發defferred.我們利用callWhenRunning 接收額外的參數然后傳遞給callback.在twisted 中有很多注冊callback 的api都遵守這個規則,包括吧callback 加進deferred 的api.

callback 和 errback 都可以停止reactor,既然defferred 支持callback 鏈和errback鏈,我們可以這些普通代碼重組進鏈的第二層,具體的代碼在這里twisted-deferred/defer-9.py:

import sys

from twisted.internet.defer import Deferred

def got_poem(poem):
????print poem

def poem_failed(err):
????print >>sys.stderr, 'poem download failed'
????print >>sys.stderr, 'I am terribly sorry'
????print >>sys.stderr, 'try again later?'

def poem_done(_):
????from twisted.internet import reactor
????reactor.stop()

d = Deferred()

d.addCallbacks(got_poem, poem_failed)
d.addBoth(poem_done)

from twisted.internet import reactor

reactor.callWhenRunning(d.callback, 'Another short poem.')

reactor.run()

addBoth 方法向callback和errback 鏈中加入了相同的函數,不論如果我們完成了重構.

Summary
在這一部分我們分析了callback 程序,知道了一些可能潛在的問題.我們也看到了Defferred是怎樣幫助我們寫代碼的:

????我們不能無視errbacks.deferred內置對errback 的支持
????多次觸發callback可能導致很難調試的bug,Deferred只能被觸發一次,你可以把他想象成try/except
????用deferred,我們可以通過向鏈中增加新的callback和errback,并在各callback 和errback中移動代碼完成重構


我們跟deferred 還沒完,它的很多原理我們還沒有講,但對于我們的poetry client已經夠用了.繼續等我們的第八部分吧.我要先去吃飯了.

總結

以上是生活随笔為你收集整理的twisted系列教程七–小插曲,延迟对象的全部內容,希望文章能夠幫你解決所遇到的問題。

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