(转) Twisted :第十九部分 改变之前的想法
2019獨(dú)角獸企業(yè)重金招聘Python工程師標(biāo)準(zhǔn)>>>
簡(jiǎn)介
Twisted是一個(gè)正在進(jìn)展的項(xiàng)目,它的開發(fā)者會(huì)定期添加新的特性并且擴(kuò)展舊的特性.
隨著Twisted 10.1.0發(fā)布,開發(fā)者向?Deferred?類添加了一個(gè)新的特性——?cancellation?——這正是我們今天要研究的.
異步編程將請(qǐng)求和響應(yīng)解耦了,如此又帶來(lái)一個(gè)新的可能性:在請(qǐng)求結(jié)果和返回結(jié)果之間,你可能決定不再需要這個(gè)結(jié)果了.考慮一下?:doc:`p14`?中的詩(shī)歌代理服務(wù)器.下面是這個(gè)如何工作的,至少對(duì)于詩(shī)歌的第一次請(qǐng)求:
一個(gè)對(duì)詩(shī)歌的請(qǐng)求來(lái)了.
這個(gè)代理聯(lián)系實(shí)際服務(wù)器以得到這首詩(shī)
一旦這首詩(shī)完成,將其發(fā)送給原發(fā)出請(qǐng)求的代理
看起來(lái)非常完美,但是如果客戶端在獲得詩(shī)歌之前掛了怎么辦?也許它們先前請(qǐng)求?Paradise Lost?的全部?jī)?nèi)容,隨后它們決定實(shí)際想要的是?Kojo?的俳句.我們的代理將陷入下載前者,并且那個(gè)慢服務(wù)器會(huì)等好一會(huì).最好的策略便是關(guān)閉連接,讓慢服務(wù)器回去順覺(jué).
回憶一下?第十五部分,展示了同步程序控制流的概念.在那張圖中我們可以看到函數(shù)調(diào)用自上而下,異常是自下而上.如果我們希望取消一個(gè)同步調(diào)用(這僅是假設(shè)),控制流的傳遞方向與函數(shù)調(diào)用的方向一致,都是從高層傳向底層,如圖38所示:
圖38:同步程序流,含假想取消操作
當(dāng)然,在同步程序中這是不可能的,因?yàn)楦邔拥拇a在底層操作結(jié)束前沒(méi)有恢復(fù)運(yùn)行,自然也就沒(méi)有什么可取消的.但是在異步程序中,高層代碼在底層代碼完成前具有控制權(quán),至少具有在底層代碼完成之前取消它的請(qǐng)求的可能性.
在Twisted程序中,底層請(qǐng)求被包含在一個(gè)?Deferred?對(duì)象中,你可以將其想象為一個(gè)外部異步操作的"句柄".?deferred?中正常的信息流是向下的,從底層代碼到高層代碼,與同步程序中返回的信息流方向一致.從Twisted 10.1.0開始,高層代碼可以反向發(fā)送信息 —— 它可以告訴底層代碼它不再需要其結(jié)果了.如圖39:
圖39:?deferred?中的信息流,包含取消
取消?Deferreds
讓我們看一些例程,來(lái)了解下取消?deferreds?的實(shí)際工作原理.注:為了運(yùn)行這些列子以及本部分中的其他代碼,你需要安裝Twisted 10.1.0或更高?版本. 考慮?deferred-cancel/defer-cancel-1.py:
from?twisted.internet?import?deferdef?callback(res):print?'callback?got:',?resd?=?defer.Deferred() d.addCallback(callback) d.cancel() print?'done'伴隨著新的取消特性,?Deferred?類獲得一個(gè)名為?cancel?的新方法.上面代碼創(chuàng)建了一個(gè)新的?deferred,添加了一個(gè)回調(diào),這后取消了這個(gè)?deferred?而沒(méi)有激發(fā)它.輸出如下:
done Unhandled?error?in?Deferred: Traceback?(most?recent?call?last): Failure:?twisted.internet.defer.CancelledError:OK,取消一個(gè)?deferred?看起來(lái)像使錯(cuò)誤回調(diào)鏈運(yùn)行,常規(guī)的回調(diào)根本沒(méi)有被調(diào)用.同樣注意到這個(gè)錯(cuò)誤是: twisted.internet.defer.CancelledError,一個(gè)意味著?deferred?被取消的個(gè)性化異常(但請(qǐng)繼續(xù)閱讀).讓我們添加一個(gè)錯(cuò)誤回調(diào),如deferred-cancel/defer-cancel-2.py
from?twisted.internet?import?deferdef?callback(res):print?'callback?got:',?resdef?errback(err):print?'errback?got:',?errd?=?defer.Deferred() d.addCallbacks(callback,?errback) d.cancel() print?'done'得到以下輸出:
errback?got:?[Failure?instance:?Traceback?(failure?with?no?frames):?<class?'twisted.internet.defer.CancelledError'>: ] done所以我們可以'捕獲'從?cancel?產(chǎn)生的錯(cuò)誤回調(diào),就像其他?deferred?錯(cuò)誤一樣.
OK,讓我們?cè)囋嚰ぐl(fā)?deferred?然后取消它,如?deferred-cancel/defer-cancel-3.py:
from?twisted.internet?import?deferdef?callback(res):print?'callback?got:',?resdef?errback(err):print?'errback?got:',?errd?=?defer.Deferred() d.addCallbacks(callback,?errback) d.callback('result') d.cancel() print?'done'這里我們用常規(guī)?callback?方法激發(fā)?deferred,之后取消它.輸出結(jié)果如下:
callback?got:?result done我們的回調(diào)被調(diào)用(正如我們所預(yù)期的)之后程序正常結(jié)束,就像?cancel?根本沒(méi)有被調(diào)用.所以取消一個(gè)?deferred?好像根本沒(méi)有效果如果它已經(jīng)被激發(fā)(但請(qǐng)繼續(xù)閱讀!).
如果我們?cè)谌∠?deferred?之后激發(fā)它會(huì)怎樣?參看?deferred-cancel/defer-cancel-4.py:
from?twisted.internet?import?deferdef?callback(res):print?'callback?got:',?resdef?errback(err):print?'errback?got:',?errd?=?defer.Deferred() d.addCallbacks(callback,?errback) d.cancel() d.callback('result') print?'done'這種情況的輸出如下:
errback?got:?[Failure?instance:?Traceback?(failure?with?no?frames):?<class?'twisted.internet.defer.CancelledError'>: ] done有意思!與第二個(gè)例子的輸出一樣,當(dāng)時(shí)沒(méi)有激發(fā)?deferred.所以如果?deferred?被取消了,再激發(fā)它沒(méi)有效果.但是為什么 d.callback('result') 沒(méi)有產(chǎn)生錯(cuò)誤,考慮到不能激發(fā)?deferred?大于一次,錯(cuò)誤回調(diào)鏈為何沒(méi)有運(yùn)行?
再次考慮?figure39.用結(jié)果或失敗激發(fā)一個(gè)?deferred?是底層代碼的工作,然而取消?deferred?是高層代碼的行為.激發(fā)deferred?意味著"這是你的結(jié)果",然而取消?deferred?意味著"我不再想要這個(gè)結(jié)果了".同時(shí)記住?cancel?是一個(gè)新特性,所以大部分現(xiàn)有的Twisted代碼并沒(méi)有處理取消的操作.但是Twisted的開發(fā)者使我們?nèi)∠?deferred?的想法變得有可能,甚至包括那些在Twisted 10.1.0之前寫的代碼.
為了實(shí)現(xiàn)以上想法,?cancel?方法實(shí)際上做兩件事:
告訴?Deferred?對(duì)象本身你不想要那個(gè)結(jié)果,如果它還沒(méi)有返回(如,?deferred?沒(méi)有被激發(fā)),這樣忽略任何回調(diào)或錯(cuò)誤回調(diào)的后續(xù)調(diào)用.
同時(shí),可選地,告訴正在產(chǎn)生結(jié)果的底層代碼需要采取何種步驟來(lái)取消操作.
由于舊版本的Twisted代碼會(huì)上前去激發(fā)任何已經(jīng)被取消的?deferred, step#1確保我們的程序不會(huì)垮掉如果我們?nèi)∠粋€(gè)舊有庫(kù)中的?deferred.
這意味著我們可以隨心所欲地取消一個(gè)?deferred,同時(shí)可以確定不會(huì)得到結(jié)果如果它還沒(méi)有到來(lái)(甚至那些?將要?到來(lái)的).但是取消?deferred?可能并沒(méi)有取消異步操作.終止一個(gè)異步操作需要一個(gè)上下文的具體行動(dòng).你可能需要關(guān)閉網(wǎng)絡(luò)連接,回滾數(shù)據(jù)庫(kù)事務(wù),結(jié)束子進(jìn)程,等等.由于?deferred?僅僅是一般目的的回調(diào)組織者,它怎么知道具體要做什么當(dāng)你取消它時(shí)?或者,換種說(shuō)法,它怎樣將?cancel?請(qǐng)求傳遞給首先已經(jīng)創(chuàng)建和返回了?deferred?的底層代碼? 和我一起說(shuō):
I?know,?with?a?callback!本質(zhì)上取消?Deferreds
好吧,首先看一下?deferred-cancel/defer-cancel-5.py:
from?twisted.internet?import?deferdef?canceller(d):print?"I?need?to?cancel?this?deferred:",?ddef?callback(res):print?'callback?got:',?resdef?errback(err):print?'errback?got:',?errd?=?defer.Deferred(canceller)?#?created?by?lower-level?code d.addCallbacks(callback,?errback)?#?added?by?higher-level?code d.cancel() print?'done'這個(gè)例子基本上跟第二個(gè)例子相同,除了有第三個(gè)回調(diào)(canceller).這個(gè)回調(diào)是我們?cè)趧?chuàng)建?Deferred?的時(shí)候傳遞給它的,不是之后添加的.這個(gè)回調(diào)負(fù)責(zé)執(zhí)行終止異步操作時(shí)所需的上下文相關(guān)的具體操作(當(dāng)然,僅當(dāng)?deferred?被實(shí)際取消).?canceller?回調(diào)是返回?deferred?的底層代碼的必要部分,不是接收?deferred?的高層代碼為其自己添加的回調(diào)和錯(cuò)誤回調(diào).
運(yùn)行這個(gè)例子將產(chǎn)生如下輸出:
I?need?to?cancel?this?deferred:?<Deferred?at?0xb7669d2cL> errback?got:?[Failure?instance:?Traceback?(failure?with?no?frames):?<class?'twisted.internet.defer.CancelledError'>: ] done正如你所看到, 不需要返回結(jié)果的?deferred?被傳遞給?canceller?回調(diào).在這里我們可以做任何需要做的事情以便徹底終止異步操作.注意?canceller?在錯(cuò)誤回調(diào)鏈激發(fā)前被調(diào)用.其實(shí)我們可以在取消回調(diào)中選擇使用任何結(jié)果或錯(cuò)誤自己激發(fā)?deferred(這樣就會(huì)優(yōu)先于?CancelledError?失敗).這兩種情況在?deferred-cancel/defer-cancel-6.py?和?deferred-cancel/defer-cancel-7.py中進(jìn)行了說(shuō)明.
在激發(fā)?reactor?之前先做一個(gè)簡(jiǎn)單的測(cè)試.我們將使用?canceller?回調(diào)創(chuàng)建一個(gè)?deferred,正常的激發(fā)它,之后取消它.你可以在?deferred-cancel/defer-cancel-8.py?中看到代碼.通過(guò)檢查那個(gè)腳本的輸出,你將看到取消一個(gè)被激發(fā)的?deferred?不會(huì)調(diào)用canceller?回調(diào).這正是我們所要的,因?yàn)闆](méi)什么可取消的.
我們目前看到的例子都沒(méi)有實(shí)際的異步操作. 讓我們構(gòu)造一個(gè)調(diào)用異步操作的簡(jiǎn)單程序,之后我們將指出如何使那個(gè)操作可取消.
參見(jiàn)代碼?deferred-cancel/defer-cancel-9.py:
from?twisted.internet.defer?import?Deferreddef?send_poem(d):print?'Sending?poem'd.callback('Once?upon?a?midnight?dreary')def?get_poem():"""Return?a?poem?5?seconds?later."""from?twisted.internet?import?reactord?=?Deferred()reactor.callLater(5,?send_poem,?d)return?ddef?got_poem(poem):print?'I?got?a?poem:',?poemdef?poem_error(err):print?'get_poem?failed:',?errdef?main():from?twisted.internet?import?reactorreactor.callLater(10,?reactor.stop)?#?stop?the?reactor?in?10?secondsd?=?get_poem()d.addCallbacks(got_poem,?poem_error)reactor.run()main()這個(gè)例子中包含了一個(gè) get_poem 函數(shù),它使用?reactor?的?callLater?方法在被調(diào)用5秒鐘后異步地返回一首詩(shī).主函數(shù)調(diào)用 get_poem,添加一個(gè)回調(diào)/錯(cuò)誤回調(diào)對(duì),之后啟動(dòng)?reactor.我們(同樣使用?callLater)安排?reactor?在10秒鐘之后停止.通常我們向?deferred?添加一個(gè)回調(diào)來(lái)實(shí)現(xiàn),但你很快就會(huì)知道我們?yōu)楹芜@樣做.
運(yùn)行程序(適當(dāng)延遲后)產(chǎn)生如下輸出:
Sending?poem I?got?a?poem:?Once?upon?a?midnight?dreary10秒鐘后程序終止.現(xiàn)在來(lái)試試在詩(shī)歌被發(fā)送前取消?deferred.只需加入以下代碼在2秒鐘后取消(在5秒鐘延遲發(fā)送詩(shī)歌之前):
reactor.callLater(2,?d.cancel)?#?cancel?after?2?seconds完整的例子參見(jiàn)?deferred-cancel/defer-cancel-10.py,這將產(chǎn)生如下輸出:
get_poem?failed:?[Failure?instance:?Traceback?(failure?with?no?frames):?<class?'twisted.internet.defer.CancelledError'>: ] Sending?poem這個(gè)例子清晰地展示了取消一個(gè)?deferred?并沒(méi)有取消它背后的異步請(qǐng)求.2秒鐘后我們看到了錯(cuò)誤回調(diào)輸出,打印出如我們所料的?CancelledError?錯(cuò)誤.但是5秒鐘后我們看到了 send_poem 的輸出(但是這個(gè)?deferred?上的回調(diào)并沒(méi)有激發(fā)).
這時(shí)我們與?deferred-cancel/defer-cancel-4.py?的情況一樣."取消"?deferred?僅僅是使最終結(jié)果被忽略,但實(shí)際上并沒(méi)有終止這個(gè)操作.正如我們上面所學(xué),為了得到一個(gè)真正可取消的?deferred,必須在它被創(chuàng)建時(shí)添加一個(gè)?cancel?回調(diào).
那么這個(gè)新的回調(diào)需要做什么呢? 參考一下關(guān)于?callLater?方法的?文檔. 它的返回值是另一個(gè)實(shí)現(xiàn)了?IDelayedCall?的對(duì)象,用?cancel?方法我們可以阻止延遲的調(diào)用被執(zhí)行.
這非常簡(jiǎn)單,更新后的代碼參見(jiàn)?deferred-cancel/defer-cancel-11.py.所有相關(guān)變化都在 get_poem 函數(shù)中:
def?get_poem():"""Return?a?poem?5?seconds?later."""def?canceler(d):#?They?don't?want?the?poem?anymore,?so?cancel?the?delayed?calldelayed_call.cancel()#?At?this?point?we?have?three?choices:#???1.?Do?nothing,?and?the?deferred?will?fire?the?errback#??????chain?with?CancelledError.#???2.?Fire?the?errback?chain?with?a?different?error.#???3.?Fire?the?callback?chain?with?an?alternative?result.d?=?Deferred(canceler)from?twisted.internet?import?reactor delayed_call?=?reactor.callLater(5,?send_poem,?d)return?d在這個(gè)新版本中,我們保存?callLater?的返回值以便能夠在?cancel?回調(diào)中使用.?cancel?回調(diào)的唯一工作是調(diào)用 delayed_call.cancel(). 但是正如之前討論的,我們可以選擇激發(fā)自定義的?deferred. 最新版本的程序產(chǎn)生如下輸出:
get_poem?failed:?[Failure?instance:?Traceback?(failure?with?no?frames):?<class?'twisted.internet.defer.CancelledError'>: ]正如你看到的,?deferred?被取消了并且異步操作被真正地終止了(我們看不到 send_poem 的輸出了).
詩(shī)歌代理 3.0
正如在簡(jiǎn)介中所討論,詩(shī)歌代理服務(wù)器是實(shí)現(xiàn)取消的很好的候選者,因?yàn)檫@可以讓我們?nèi)∠?shī)歌下載如果事實(shí)證明沒(méi)有人想要它(如客戶端已經(jīng)在我們發(fā)送詩(shī)歌前關(guān)閉了連接).版本 3.0的代理位于?twisted-server-4/poetry-proxy.py,實(shí)現(xiàn)了?deferred?取消. 變化首先位于?PoetryProxyProtocol:
class?PoetryProxyProtocol(Protocol):def?connectionMade(self):self.deferred?=?self.factory.service.get_poem()self.deferred.addCallback(self.transport.write)self.deferred.addBoth(lambda?r:?self.transport.loseConnection())def?connectionLost(self,?reason):if?self.deferred?is?not?None:deferred,?self.deferred?=?self.deferred,?Nonedeferred.cancel()?#?cancel?the?deferred?if?it?hasn't?fired你可以與?舊版本?對(duì)比一下.兩個(gè)主要的變化是:
保存我們從 get_poem 得到的?deferred,以便之后在需要時(shí)取消它.
當(dāng)連接關(guān)閉時(shí)取消?deferred.注這個(gè)操作同樣會(huì)取消?deferred?當(dāng)我們實(shí)際得到詩(shī)歌之后,但正如前例所發(fā)現(xiàn)的,取消一個(gè)被激發(fā)的?deferred?不會(huì)有任何效果.
現(xiàn)在我們需要確保取消?deferred?將實(shí)際終止詩(shī)歌的下載. 所以我們需要改變?ProxyService:
class?ProxyService(object):poem?=?None?#?the?cached?poemdef?__init__(self,?host,?port):self.host?=?hostself.port?=?portdef?get_poem(self):if?self.poem?is?not?None:print?'Using?cached?poem.'#?return?an?already-fired?deferredreturn?succeed(self.poem)def?canceler(d):print?'Canceling?poem?download.'factory.deferred?=?Noneconnector.disconnect()print?'Fetching?poem?from?server.'deferred?=?Deferred(canceler)deferred.addCallback(self.set_poem)factory?=?PoetryClientFactory(deferred)from?twisted.internet?import?reactorconnector?=?reactor.connectTCP(self.host,?self.port,?factory)return?factory.deferreddef?set_poem(self,?poem):self.poem?=?poemreturn?poem同樣,可以與?舊版本?對(duì)比一下. 這個(gè)類具有一些新的變化:
我們保存 reactor.connetTCP 的返回值,一個(gè)?IConnector?對(duì)象.我們可以使用這個(gè)對(duì)象上的?disconnect?方法關(guān)閉連接.
我們創(chuàng)建帶?canceler?回調(diào)的?deferred.那個(gè)回調(diào)是一個(gè)閉包,它使用?connector?關(guān)閉連接. 但首先須設(shè)置 factory.deferred 屬性為 None. 否則,工廠會(huì)以 "連接關(guān)閉"錯(cuò)誤回調(diào)激發(fā)?deferred?而不是以?CancelledError?激發(fā). 由于deferred?已經(jīng)被取消了, 以?CancelledError?激發(fā)更加合適.
你同樣會(huì)注意到我們是在?ProxyService?中創(chuàng)建?deferred?而不是?PoetryClientFactory. 由于?canceler?回調(diào)需要獲取IConnector?對(duì)象,?ProxyService?成為最方便創(chuàng)建?deferred?的地方.
同時(shí),就像我們之前的例子,?canceler?回調(diào)作為一個(gè)閉包實(shí)現(xiàn).閉包看起來(lái)在取消回調(diào)的實(shí)現(xiàn)上非常有用.
讓我們?cè)囋囆碌拇?首先啟動(dòng)一個(gè)慢服務(wù)器.它需要很慢以便我們有時(shí)間取消:
python?blocking-server/slowpoetry.py?--port?10001?poetry/fascination.txt現(xiàn)在可以啟動(dòng)代理(記住你需要Twisted 10.1.0):
python?twisted-server-4/poetry-proxy.py?--port?10000?10001現(xiàn)在我們可以用任何客戶端從代理下載一首詩(shī),或者僅使用 curl:
curl?localhost:10000幾秒鐘后,按?Ctrl-C?停止客戶端或者 curl 進(jìn)程. 在終端運(yùn)行代理你將看到如下輸出:
Fetching?poem?from?server. Canceling?poem?download.你應(yīng)該看到慢服務(wù)器已經(jīng)停止了向輸出打印它所發(fā)送詩(shī)歌的片段,因?yàn)槲覀兊拇頀炝?
你可以多次啟動(dòng)和停止客戶端來(lái)證實(shí)每個(gè)下載每次都被取消了.但是如果你讓整首詩(shī)運(yùn)行完,那么代理將緩存它并且在此之后立即發(fā)送它.
另一個(gè)難點(diǎn)
以上我們?cè)恢挂淮握f(shuō)取消一個(gè)已經(jīng)激發(fā)的?deferred?是沒(méi)有效果的.然而,這不是十分正確.在?:doc:`p13`?中,我們學(xué)習(xí)了附加給一個(gè)?deferred?的回調(diào)和錯(cuò)誤回調(diào)也可能返回另一個(gè)?deferred.在那種情況下,原始的(外層)?deferred?暫停執(zhí)行它的回調(diào)鏈并且等待內(nèi)層?deferred?激發(fā)(參見(jiàn)?`figure28`_).
如此, 即使一個(gè)?deferred?激發(fā)了發(fā)出異步請(qǐng)求的高層代碼,它也不能接收到結(jié)果,因?yàn)樵诘却齼?nèi)層?deferred?完成之前回調(diào)鏈暫停了. 所以當(dāng)高層代碼取消這個(gè)外部?deferred?時(shí)會(huì)發(fā)生什么情況呢? 在這種情況下,外部?deferred?不僅僅是取消它自己(它已經(jīng)激發(fā)了);相反地,這個(gè)?deferred?取消內(nèi)部的?deferred.
所以當(dāng)你取消一個(gè)?deferred?時(shí),你可能不是在取消主異步操作,而是一些其他的作為前者結(jié)果所觸發(fā)的異步操作.呼!
我們可以用一個(gè)例子來(lái)說(shuō)明.考慮代碼?deferred-cancel/defer-cancel-12.py:
from?twisted.internet?import?deferdef?cancel_outer(d):print?"outer?cancel?callback."def?cancel_inner(d):print?"inner?cancel?callback."def?first_outer_callback(res):print?'first?outer?callback,?returning?inner?deferred'return?inner_ddef?second_outer_callback(res):print?'second?outer?callback?got:',?resdef?outer_errback(err):print?'outer?errback?got:',?errouter_d?=?defer.Deferred(cancel_outer) inner_d?=?defer.Deferred(cancel_inner)outer_d.addCallback(first_outer_callback) outer_d.addCallbacks(second_outer_callback,?outer_errback)outer_d.callback('result')#?at?this?point?the?outer?deferred?has?fired,?but?is?paused #?on?the?inner?deferred.print?'canceling?outer?deferred.' outer_d.cancel()print?'done'在這個(gè)例子中,我們創(chuàng)建了兩個(gè)?deferred, outer 和 inner,并且有一個(gè)外部回調(diào)返回內(nèi)部?deferred. 首先,我們激發(fā)外部deferred,然后取消它. 輸出結(jié)果如下:
first?outer?callback,?returning?inner?deferred canceling?outer?deferred. inner?cancel?callback. outer?errback?got:?[Failure?instance:?Traceback?(failure?with?no?frames):?<class?'twisted.internet.defer.CancelledError'>: ] done正如你看到的,取消外部?deferred?并沒(méi)有使外部?cancel?回調(diào)被激發(fā). 相反,它取消了內(nèi)部?deferred,所以內(nèi)部?cancel?回調(diào)被激發(fā)了,之后外部錯(cuò)誤回調(diào)收到?CancelledError?(來(lái)自內(nèi)部?deferred).
你可能需要仔細(xì)看一看那些代碼,并且做些變化看看如何影響結(jié)果.
討論
取消?deferred?是非常有用的操作,使我們的程序避免去做不需要的工作. 然而正如我們看到的,它可能有一點(diǎn)點(diǎn)棘手.
需要明白的一個(gè)重要事實(shí)是取消一個(gè)?deferred?并不意味著取消了它后面的異步操作.事實(shí)上,當(dāng)寫這篇文章時(shí),很多?deferreds并不會(huì)被真的"取消",因?yàn)榇蟛糠諸wisted代碼寫于Twisted 10.1.0之前并且還沒(méi)有被升級(jí).這包括很多Twisted本身的APIs!檢查文檔或源代碼去發(fā)現(xiàn)"取消?deferred"是否真的取消了背后的請(qǐng)求,還是僅僅忽略它.
第二個(gè)重要事實(shí)是從你的異步APIs返回的?deferred?并不一定在完整意義上可取消. 如果你希望在自己的程序中實(shí)現(xiàn)取消,你應(yīng)該先研究一下Twisted源代碼中的許多例子.?Cancellation?是一個(gè)暫新的特性,所以它的模式和最好實(shí)踐還在制定當(dāng)中.
展望未來(lái)
現(xiàn)在我們已經(jīng)學(xué)習(xí)了關(guān)于?Deferreds?的方方面面以及Twisted背后的核心概念. 這意味著我們沒(méi)什么需要介紹的了,因?yàn)門wisted的其余部分主要包括一些特定的應(yīng)用,如網(wǎng)絡(luò)編程或異步數(shù)據(jù)庫(kù)處理.故而,在?接下來(lái)?的部分中,我們想走點(diǎn)彎路,看看其他兩個(gè)使用異步I/O的系統(tǒng)跟Twisted有何理念相似之處.之后,在尾聲中,我們會(huì)打個(gè)包并且建議一些幫助你繼續(xù)學(xué)習(xí)Twisted的方法.
參考練習(xí)
你知道你可以用多種方式拼寫"cancelled"嗎??真的. 這取決于你的心情.
細(xì)讀?Deferred?類的源代碼,關(guān)注?cancellation?的實(shí)現(xiàn).
在Twisted 10.1.0的?源碼?中找具有取消回調(diào)的?deferred?的例子.研究它們的實(shí)現(xiàn).
修改我們?cè)姼杩蛻舳酥?get_poetry 方法返回的?deferred, 使其可取消.
做一個(gè)基于 reactor 的例子展示取消外部?deferred,它被內(nèi)層?deferred?暫停了.如果使用?callLater?你需要小心選擇延遲時(shí)間,以確保外層?deferred?在正確的時(shí)刻被取消.
找一個(gè) Twisted 中還不支持"本質(zhì)上取消操作"的異步API,為它實(shí)現(xiàn)本質(zhì)取消. 并向 Twisted項(xiàng)目 提交一個(gè)?補(bǔ)丁.不要忘記單元測(cè)試!
轉(zhuǎn)載于:https://my.oschina.net/CandyMi/blog/610325
總結(jié)
以上是生活随笔為你收集整理的(转) Twisted :第十九部分 改变之前的想法的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Gmap.net 怎么导入离线地图
- 下一篇: 线性筛法求素数