您問題中的代碼只知道如何跟蹤一個Deferred
。如果應用程序代碼調用getInfo
兩次沒有足夠的間隔時間爲第一個動作完成與結果,那麼它會破壞自己的內部跟蹤狀態:
def getInfo(self,request):
print 'sending', request
self.d = defer.Deferred()
self.sendLine(request)
return self.d
d_foo = getInfo(foo)
d_bar = getInfo(bar)
在這個序列中,d_foo
和d_bar
不同Deferred
實例。但是,在第二次調用getInfo
時,屬性self.d
的值從d_foo
更改爲d_bar
。 d_foo
Deferred
丟失。後來,當`lineReceived運行:
def lineReceived(self, line):
line = line.strip()
self.buffer.append(line)
if self.d is None:
return
if 'result_I_want' in self.buffer:
print 'Firing Callback'
self.d.callback(self.buffer)
self.d
是d_bar
即使線可能是在FOO請求的響應。這意味着d_bar
將得到foo的響應和d_foo
永遠不會得到任何響應。
要解決此問題,可能有助於在協議上保留Deferred
實例的列表(或隊列)。在發出新的信息請求時附加到它,當收到響應時從它的前面彈出。 (我不確定你正在執行什麼協議,所以我不知道你將如何決定有多少行可以構成響應。如果協議沒有定義這個,那麼它會被破壞,你可能想要切換到更好的協議。)
如果您修復此問題,那麼響應至少會傳遞到不同的Deferred
實例。
您還描述了與強制順序操作有關的問題。有幾種方法可以解釋這一點。一種方法是將其解釋爲意味着您只希望一次請求在網絡上「突出」。換句話說,你不希望getInfo
到發送新的請求行,直到後lineReceived
交付響應數據由以前調用getInfo
返回Deferred
。
在這種情況下,遞延鏈接只是事情。儘管事實上你有N個Deferreds,但當你施加這個順序限制時,實際上你有一系列2個Deferreds。您有延遲運行較早和延遲,應該只在較早的結果後運行。您將此延伸至N,然後再考慮後面的延遲爲新對中的較早延遲,並且第三個延遲變爲新的延遲。
或者換一種說法,如果你有D1,D2,D3和D4,然後你把它們連這樣的:
D2 is chained to D1 and only runs when D1 is complete
D3 is chained to D2 and only runs when D2 is complete
D4 is chained to D3 and only runs when D3 is complete
不過,雖然這可以工作,它實際上沒有實現序列化的最簡單方法。相反,我建議您明確地排隊工作getInfo
並明確unqueueing它lineReceived
。
def _sendRequest(self, d, request):
print 'sending', request
self.d = d
self.sendLine(request)
def getInfo(self,request):
if self.d is None:
d = defer.Deferred()
self._sendRequest(d, request)
return d
else:
queued_d = defer.Deferred()
self._requests.append((request, queued_d))
return queued_d
def lineReceived(self, line):
line = line.strip()
self.buffer.append(line)
if self.d is None:
return
if 'result_I_want' in self.buffer:
print 'Firing Callback'
now_d = self.d
self.d = None
buffer = self.buffer
self.buffer = []
if self._requests:
request, queued_d = self._requests.pop(0)
self._sendRequest(queued_d, request)
now_d.callback(buffer)
請注意,在lineReceived
的代碼需要把一切都達成一致的狀態的now_d.callback(buffer)
前行。這是一個微妙而重要的點。可以存在於now_d
回調其影響的方案 - 例如,通過再次調用getInfo
。在使代碼運行之前,協議處於一致狀態非常重要,否則它會變得混亂 - 可能是因爲發送請求失序,或者在實際發送請求時排隊請求。這是使代碼安全的示例,其針對重入。這不是Twisted使用程序所特有的想法,但是由於人們經常將再入侵的想法與線程化程序聯繫起來,人們在編寫基於Twisted的代碼時往往會忽視這種可能性。
我曾經得到過讓·保羅最清楚最全面的答案之一,非常感謝。 – Marcus1219 2013-03-26 15:13:51