【问题标题】:Twisted callback loop blocking further data from being recieved扭曲的回调循环阻止接收更多数据
【发布时间】:2015-04-29 15:29:40
【问题描述】:

当回调循环在 Twisted 中运行时,我的印象是反应器仍然能够从服务器发送/接收数据,因为它能够在回调“之间”运行。但是,当我运行下面的脚本时,它完全忽略了 self.transport.write() 行。该服务器只是 Twisted 在其网站上的基本回显服务器。

from twisted.internet import reactor, protocol
from twisted.internet.defer import Deferred


class EchoClient(protocol.Protocol):

    deferred = Deferred()

    def connectionMade(self):
        self.deferred.addCallback(self.doThing)
        self.deferred.callback(0)

    def doThing(self, _):
        print 'xxx'
        self.transport.write('Hello, world!')
        self.deferred.addCallback(self.doThing)

    def dataReceived(self, data):
        "As soon as any data is received, write it back."
        print "Server said:", data
        self.transport.loseConnection()


class EchoFactory(protocol.ClientFactory):

    protocol = EchoClient


def main():
    f = EchoFactory()
    reactor.connectTCP('192.168.0.7', 8000, f) # Correctly connected to my server
    reactor.run()

if __name__ == '__main__':
    main()

我预计会打印一个,甚至几个“xxx”,然后服务器会发送“Hello, world!”的回显回到我身边,然后更多的'xxx'。相反,我得到的是“xxx”的无限滚动,甚至没有尝试发送“你好,世界!”到服务器。我错过了什么/误解了什么?

【问题讨论】:

  • 你真的应该使用endpoints,而不是直接调用connectTCP
  • 另外,deferred = Deferred() 实例化了一个在EchoClient 的所有实例之间共享的单个Deferred 实例,这是一种反模式。您应该将self.deferred 初始化为connectionMade 的第一行。
  • 也可以考虑使用react,而不是直接运行reactor。

标签: python callback twisted deferred


【解决方案1】:

问题是您的示例永远不会让主循环运行。

建立连接后,您向self.deferred 添加回调 - 我不确定self.deferred 应该代表什么操作,但显然没有什么用处。

然后您立即(同步)回拨self.deferred。这会立即执行doThing,它调用self.transport.write。这会在主循环下次运行时将一些字节添加到要发送的传出缓冲区。然后,在该回调中,您立即(同步)向self.deferred 添加另一个回调,该回调将在当前回调完成后立即运行。所以我们进入doThing,它调用self.transport.write。我们还没有写任何东西,更不用说读任何东西来传递给dataReceived,因为我们还没有回到主循环。但是我们向该Deferred 添加了另一个回调。再次调用doThing

这将永远持续下去,当您缓冲不断增加的传出流量时,会在传输上分配无限量的内存,但绝不允许程序从 connectionMade 返回,使其返回主循环,并且等待可写性和可读性事件。

我不知道如何修复此程序,因为不清楚您要尝试做什么,但无论如何,这不是方法:)。

【讨论】:

  • 你是说主反应器被阻塞直到回调链执行完成?我的印象是反应堆在每次回调/错误返回后“重新获得控制”(我希望这是有道理的)
  • 这也是我的印象。否则,你为什么要使用延迟而不是常规方法?
  • Deferreds 根本没有与 reactor 集成。事实上,您可以通过pypi.python.org/pypi/deferred 在完全在 Twisted 之外的程序中使用 Deferreds。 Deferred 只是一个尚未到达的结果;当您调用.callback 方法时,将传递结果并执行回调链。您使用 Deferred 而不是“常规方法”的原因是,如果您有一个稍后返回结果的函数,则 Deferred 是一个可以 return 并允许其调用者传回的值.
  • 如果你想要一些能让你屈服于反应器循环的东西,你可以使用cooperate API 和一个周期性产生的生成器。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-10-19
  • 2012-10-16
  • 1970-01-01
  • 1970-01-01
  • 2014-12-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多