顺序排列扭曲的多个延迟

Mar*_*219 4 python twisted

目前我仍然是一个扭曲的初学者,这让我感到烦恼.

我正在通过TCP发送一系列命令并等待lineRecieved阅读器的响应,这可能需要几秒钟的时间来处理和到达,所以我把它包装在一个deferred中.第一个延迟工作正常但第二个工作正在激活,因为第一个仍处理导致垃圾,因为端点一次只能处理一个命令.asysc系统中的预期行为,但不是我需要发生的行为.如果我有一个或两个命令,我可以使用deferredChain来处理,但由于我可能有几十个命令按顺序运行,我担心这会变成无法维护的意大利面.

干净的方法是什么?

非常感谢

示例代码

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)
Run Code Online (Sandbox Code Playgroud)

Jea*_*one 5

您问题中的代码只知道如何跟踪一个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)
Run Code Online (Sandbox Code Playgroud)

在这个序列中,d_foo并且d_bar是不同的Deferred实例.然而,在第二次调用getInfo时,该属性值self.d是从改变d_food_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)
Run Code Online (Sandbox Code Playgroud)

self.dd_bar即使该行是有可能到的响应FOO请求.这意味着d_bar将获得foo的响应,并且d_foo永远不会得到任何响应.

要解决此问题,可能有助于Deferred在协议上保留实例的列表(或队列).在发出新的信息请求时附加到它,当收到响应时从它的前面弹出.(我不确定你正在实施什么协议,所以我不知道你将如何决定多少行足以构成一个响应.如果协议没有定义这个,那么它就会被打破,你可能想要切换到更好的协议.)

如果您解决了这个问题,那么响应将至少传递到不同的Deferred实例.

您还描述了与强制顺序操作相关的问题.我可以通过几种方式来解释这一点.一种方法是将其解释为意味着您一次只希望一个请求在网络上"出色".换句话说,你不想getInfo发送,直到后的新请求线lineReceived已交付响应数据到Deferred由返回以前的调用getInfo.

在这种情况下,延迟链接就是问题所在.尽管你有N个Deferreds,但当你施加这个顺序限制时,你实际上有一系列2个Deferreds.你有早期运行的延迟和延迟,只有在前一个运行结果后才能运行.您将此扩展为N,然后考虑后面的Deferred为新对中的Deferred,而第三个Deferred成为新的后续Deferred.

换句话说,如果你有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
Run Code Online (Sandbox Code Playgroud)

但是,虽然这可以工作,但它实际上并不是实现序列化的最简单方法.相反,我建议明确排队工作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)
Run Code Online (Sandbox Code Playgroud)

请注意,在lineReceived该代码需要把一切都达成一致的状态之前now_d.callback(buffer)线.这是一个微妙但重要的观点.可能存在now_d影响协议的回调- 例如,通过getInfo再次呼叫.在使代码运行之前协议处于一致状态非常重要,否则会混淆 - 可能是通过无序发送请求,或者在实际发送请求时排队请求.这是使代码安全以防止重入的一个例子.这不是一个想法,是唯一使用双绞线方案,但由于人重入螺纹方案的想法最常联系起来,人们编写基于双绞线的代码时常常忽略的可能性.