Python、Twisted、Django、reactor.run() 导致问题

发布于 2024-10-09 09:24:17 字数 606 浏览 8 评论 0原文

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

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

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

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

I have a Django web application. I also have a spell server written using twisted running on the same machine having django (running on localhost:8090). The idea being when user does some action, request comes to Django which in turn connects to this twisted server & server sends data back to Django. Finally Django puts this data in some html template & serves it back to the user.

Here's where I am having a problem. In my Django app, when the request comes in I create a simple twisted client to connect to the locally run twisted server.

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

The reactor.run() is causing a problem. Since it's an event loop. The next time this same code is executed by Django, I am unable to connect to the server. How does one handle this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

晨曦慕雪 2024-10-16 09:24:17

上面两个答案都是正确的。但是,考虑到您已经实现了一个拼写服务器,然后将其作为一个服务器运行。您可以首先在同一台计算机上将其作为单独的进程运行 - 在 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 界面也可以轻松地在反向代理负载均衡器后面水平扩展它。

The above two answers are correct. However, considering that you've already implemented a spelling server then run it as one. You can start by running it on the same machine as a separate process - at localhost:PORT. Right now it seems you have a very simple binary protocol interface already - you can implement an equally simple Python client using the standard lib's socket interface in blocking mode.

However, I suggest playing around with twisted.web and expose a simple web interface. You can use JSON to serialize and deserialize data - which is well supported by Django. Here's a very quick example:

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())

And to run it you can use the following skeleton .tac file:

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)

Running your service as another first class service allows you to run it on another machine one day if you find the need - exposing a web interface makes it easy to horizontally scale it behind a reverse proxying load balancer too.

你怎么敢 2024-10-16 09:24:17

reactor.run() 在整个程序中应该只调用一次。不要将其视为“启动我的这一请求”,而将其视为“启动所有 Twisted”。

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

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

reactor.run() should be called only once in your whole program. Don't think of it as "start this one request I have", think of it as "start all of Twisted".

Running the reactor in a background thread is one way to get around this; then your django application can use blockingCallFromThread in your Django application and use a Twisted API as you would any blocking API. You will need a little bit of cooperation from your WSGI container, though, because you will need to make sure that this background Twisted thread is started and stopped at appropriate times (when your interpreter is initialized and torn down, respectively).

You could also use Twisted as your WSGI container, and then you don't need to start or stop anything special; blockingCallFromThread will just work immediately. See the command-line help for twistd web --wsgi.

煮酒 2024-10-16 09:24:17

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

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

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

You should stop reactor after you got results from Twisted server or some error/timeout happening. So on each Django request that requires query your Twisted server you should run reactor and then stop it. But, it's not supported by Twisted library — reactor is not restartable. Possible solutions:

  • Use separate thread for Twisted reactor, but you will need to deploy your django app with server, which has support for long running threads (I don't now any of these, but you can write your own easily :-)).

  • Don't use Twisted for implementing client protocol, just use plain stdlib's socket module.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文