【问题标题】:Python, Twisted, Django, reactor.run() causing problemPython,Twisted,Django,reactor.run() 导致问题
【发布时间】:2011-05-30 21:39:42
【问题描述】:

我有一个 Django 网络应用程序。我还有一个使用 twisted 编写的拼写服务器,运行在具有 django 的同一台机器上(在localhost:8090 上运行)。这个想法是当用户执行某些操作时,请求来到 Django,后者又连接到这个扭曲的服务器,服务器将数据发送回 Django。最后,Django 将这些数据放入一些 html 模板中并提供给用户。

这就是我遇到问题的地方。在我的 Django 应用程序中,当请求进来时,我创建了一个简单的扭曲客户端来连接到本地运行的扭曲服务器。

...
        factory = Spell_Factory(query) 
        reactor.connectTCP(AS_SERVER_HOST, AS_SERVER_PORT, factory)
        reactor.run(installSignalHandlers=0)
        print factory.results
...

reactor.run() 引起了问题。因为它是一个事件循环。下次 Django 执行相同的代码时,我无法连接到服务器。如何处理?

【问题讨论】:

    标签: python django twisted twisted.client twisted.internet


    【解决方案1】:

    从 Twisted 服务器获得结果或发生错误/超时后,您应该停止反应器。因此,对于需要查询 Twisted 服务器的每个 Django 请求,您应该运行 reactor 然后停止它。但是,Twisted 库不支持它——reactor 不可重新启动。可能的解决方案:

    • 为 Twisted reactor 使用单独的线程,但您需要使用服务器部署 django 应用程序,该服务器支持长时间运行的线程(我现在没有这些,但您可以轻松编写自己的线程: -))。

    • 不要使用 Twisted 来实现客户端协议,只需使用普通 stdlib 的 socket 模块。

    【讨论】:

      【解决方案2】:

      reactor.run() 在整个程序中只能调用一次。不要把它想象成“开始我的这个请求”,把它想象成“开始所有的 Twisted”。

      在后台线程中运行反应器是解决此问题的一种方法;那么您的 django 应用程序可以在您的 Django 应用程序中使用 blockingCallFromThread 并像使用任何阻塞 API 一样使用 Twisted API。不过,您将需要 WSGI 容器的一点配合,因为您需要确保在适当的时间启动和停止此后台 Twisted 线程(分别在初始化和拆除解释器时)。

      你也可以使用 Twisted 作为你的 WSGI 容器,然后你不需要启动或停止任何特殊的东西; blockingCallFromThread 将立即工作。请参阅twistd web --wsgi 的命令行帮助。

      【讨论】:

        【解决方案3】:

        以上两个答案都是正确的。但是,考虑到您已经实现了一个拼写服务器,然后将其作为一个服务器运行。您可以首先在同一台机器上作为单独的进程运行它 - 在localhost:PORT。现在看来您已经有了一个非常简单的二进制协议接口——您可以在阻塞模式下使用标准库的socket 接口实现同样简单的 Python 客户端。

        但是,我建议使用 twisted.web 并公开一个简单的 Web 界面。您可以使用 JSON 来序列化和反序列化数据 - Django 很好地支持这一点。这是一个非常简单的示例:

        import json
        from twisted.web import server, resource
        from twisted.python import log
        
        class Root(resource.Resource):
            def getChild(self, path, request):
                # represents / on your web interface
                return self
        
        class WebInterface(resource.Resource):
            isLeaf = True
            def render_GET(self, request):
                log.msg('GOT a GET request.')
                # read request.args if you need to process query args
                # ... call some internal service and get output ...
                return json.dumps(output)
        
        class SpellingSite(server.Site):
            def __init__(self, *args, **kwargs):
                self.root = Root()
                server.Site.__init__(self, self.root, **kwargs)
                self.root.putChild('spell', WebInterface())
        

        要运行它,您可以使用以下骨架 .tac 文件:

        from twisted.application import service, internet
        
        site = SpellingSite()
        application = service.Application('WebSpell')
        # attach the service to its parent application
        service_collection = service.IServiceCollection(application)
        internet.TCPServer(PORT, site).setServiceParent(service_collection)
        

        将您的服务作为另一个一流的服务运行,如果您发现需要,您可以在某天在另一台机器上运行它 - 公开 Web 界面也可以很容易地在反向代理负载均衡器后面水平扩展它。

        【讨论】:

          猜你喜欢
          • 2015-11-07
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多