目前,我仍然是一个在扭曲的初学者,这使我烦恼。
我正在通过TCP发送一系列命令,等待lineRecieved读取器的响应,这可能需要几秒钟的时间来处理和到达,所以我将其打包为延迟。第一个延迟运行很好,但是第二个触发,因为第一个仍然在处理中,导致垃圾,因为端点一次只能处理一个命令。在asysc系统中的预期行为,但不是我需要发生的行为。如果我有一两个命令,我可以使用deferedChain来处理,但是由于我可能有几十个命令要顺序运行,我担心这会很快变成不可维护的意大利面。
做这件事的清洁方法是什么?
非常感谢
示例代码
def connectionMade(self):
self.fire_def('command1')
print'fire command 2'
self.fire_def('command2')#Fires when command one is running
def fire_def(self,request):
d = self.getInfo(request)
d.addCallback(self.print_result)
return d
def print_result(result):
print result
def getInfo(self,request):
print 'sending', request
self.d = defer.Deferred()
self.sendLine(request)
return self.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'
self.d.callback(self.buffer)发布于 2013-03-26 13:39:53
您问题中的代码只知道如何跟踪一个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中显式地排队工作,并在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的代码时往往忽略了这种可能性。
发布于 2013-03-25 23:24:55
基本上,如果您希望一个接一个地执行,您将从另一个返回延迟。
因此,您希望d2只在d1完成后执行,然后,从D1的回调返回d2。
换句话说,根据您的示例,您需要在命令1回调结束时的某个地方调用command2。
https://stackoverflow.com/questions/15620978
复制相似问题