首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >双绞线中的顺序排队多重延迟

双绞线中的顺序排队多重延迟
EN

Stack Overflow用户
提问于 2013-03-25 17:22:41
回答 2查看 1.2K关注 0票数 4

目前,我仍然是一个在扭曲的初学者,这使我烦恼。

我正在通过TCP发送一系列命令,等待lineRecieved读取器的响应,这可能需要几秒钟的时间来处理和到达,所以我将其打包为延迟。第一个延迟运行很好,但是第二个触发,因为第一个仍然在处理中,导致垃圾,因为端点一次只能处理一个命令。在asysc系统中的预期行为,但不是我需要发生的行为。如果我有一两个命令,我可以使用deferedChain来处理,但是由于我可能有几十个命令要顺序运行,我担心这会很快变成不可维护的意大利面。

做这件事的清洁方法是什么?

非常感谢

示例代码

代码语言:javascript
复制
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)
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2013-03-26 13:39:53

您问题中的代码只知道如何跟踪一个Deferred。如果应用程序代码两次调用getInfo,但没有足够的间隔时间来完成第一个操作,那么它将破坏自己的内部跟踪状态:

代码语言:javascript
复制
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_food_bar是不同的Deferred实例。但是,在第二次调用getInfo时,属性self.d的值从d_foo更改为d_bard_foo Deferred迷路了。稍后,当“`lineReceived”运行时:

代码语言:javascript
复制
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.dd_bar,尽管行可能是对foo请求的响应。这意味着d_bar将获得foo的响应,而d_foo将永远不会得到任何响应。

要解决此问题,可能有助于在协议中保留Deferred实例的列表(或队列)。当一个新的信息请求被添加到它之后,当收到一个回复时,从它的前面弹出。(我不知道您正在实现什么协议,所以我不知道您将如何决定多少行足以构成响应。如果协议没有定义这一点,那么它就被破坏了,您可能希望切换到更好的协议。)

如果您修复了这个问题,那么响应至少会被传递给不同的Deferred实例。

您还描述了一个与强制顺序操作相关的问题。有几种方法我可以解释这一点。一种方法是将其解释为一次只希望一个请求在网络上“突出”。换句话说,您不希望getInfo发送新的请求行,直到lineReceived将响应数据传递到以前调用getInfo时返回的Deferred

在这种情况下,延迟链接就是问题所在。尽管您有N个Deferreds,当您强制执行这个顺序限制时,您实际上有一系列的2个Deferreds。您有运行得更早的延迟,而只能在早期运行的结果之后才会运行的延迟。然后,将其扩展到N,将后期延迟视为新对中的早期延迟,而第三个延迟将成为新的延迟。

或者换句话说,如果您有D1、D2、D3和D4,那么您可以像:

代码语言:javascript
复制
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:中显式地取消排队。

代码语言:javascript
复制
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的代码时往往忽略了这种可能性。

票数 5
EN

Stack Overflow用户

发布于 2013-03-25 23:24:55

基本上,如果您希望一个接一个地执行,您将从另一个返回延迟。

因此,您希望d2只在d1完成后执行,然后,从D1的回调返回d2。

换句话说,根据您的示例,您需要在命令1回调结束时的某个地方调用command2。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/15620978

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档