1

我有以下问题。

我在基于龙卷风的应用程序服务器上工作。大多数代码可以是同步的,Web 界面并没有真正使用 Tornado 的任何异步功能。

我现在必须连接到一个(异步)遗留后端,我使用该tornado.iostream接口发送命令。对这些命令的响应与其他定期信息(例如状态更新)一起异步发送。

代码封装在一个公共接口中,该接口也用于其他后端。

我想要实现的是以下内容:

# this is executed on initialization
self.stream.read_until_close(self.close, self.read_from_backend)

# this is called whenever data arrives on the input stream
def read_from_backend(self, data):
     if data in pending:
         # it means we got a response to a request we sent out
         del self.pending[data]
     else:
         # do something else

# this sends a request to the backend
def send_to_backend(self, data):
     self.pending[data] = True
     while data in self.pending:
          # of course this does not work
          time.sleep(1)
     return 

当然这不起作用,因为time.sleep(1)不允许read_from_backend()进一步运行。

我该如何解决这个问题?我希望send_to_backend()仅在收到响应时返回。有没有一种方法可以让我控制read_from_backend而不从该方法返回?

请注意,在 web 层使用 @asynchronous 和 @gen.engine 很难做到这一点,因为这需要完全重写我们 web 层中的所有请求。有没有办法可以在其他地方实现相同的设计模式?

4

1 回答 1

1

我认为一个好主意可能是考虑使用 gevent。通过 MonkeyPatching 并使用我编写的简单装饰器,您可以轻松获得以同步方式(阻塞样式)编写的漂亮异步视图。

您可以重用我之前回答中的大部分代码。

尽管您可能出于不同的原因不想使用 gevent(没有依赖项):

承认你已经用猴子修补了你的全局流程:

from gevent import monkey; monkey.patch_all()

上面的补丁线程,套接字,睡眠......所以他们通过gevent的集线器(集线器是gevent ioloop是龙卷风)。

一旦修补并在我之前的答案中使用 @gasync 装饰器,您的视图可能只是:

class MyHandler(tornado.web.RequestHandler):
     @gasync
     def get(self):
         # Parse the input data in some fashion
         data = get_data_from_request()

         # This could be anything using python sockets, urllib ...
         backend_response = send_data_to_backend(data)

         # Write data to HTTP client
         self.write(backend_response)

         # You have to finish the response yourself since it's asynchronous
         self.finish()

我发现 gevent 的简单性和“优雅”远远超过了使用 tornado 的 ioloop 编写异步代码的任何优势。

在我的情况下,我必须使用以同步方式编写的遗留代码,所以基本上 gevent 是一种更安全的生活,我所要做的就是猴子补丁并编写那个装饰器,我可以使用所有这些遗留代码而无需任何修改。

我希望这有帮助。

于 2012-11-10T12:13:25.133 回答