如何在Tornado中将异步和gen函数包装在一起?

时间:2014-12-15 10:12:24

标签: asynchronous generator tornado

如何在Tornado中将异步和gen函数包装在一起? 我的代码如下所示,错误是'Future'对象没有属性'body'。

我是否以错误的方式放置装饰器?

import tornado.httpclient
import tornado.web
import tornado.gen
import tornado.httpserver
import tornado.ioloop

class Class1(tornado.web.RequestHandler):

    @tornado.web.asynchronous
    def post(self, *args, **kwargs):
        url = self.get_argument('url', None)
        response = self.json_fetch('POST', url, self.request.body)
        self.write(response.body)
        self.finish()

    @tornado.gen.engine
    def json_fetch(self, method, url, body=None, *args, **kwargs):
        client = tornado.httpclient.AsyncHTTPClient()
        headers = tornado.httputil.HTTPHeaders({"content-type": "application/json charset=utf-8"})
        request = tornado.httpclient.HTTPRequest(url, method, headers, body)
        yield tornado.gen.Task(client.fetch, request)

3 个答案:

答案 0 :(得分:2)

此代码示例中不需要“异步”。 “gen.engine”已经过时,请改用“coroutine”。这些天你通常不需要使用“gen.Task”。对代码进行四处更改:

  1. 在“coroutine”中包裹“post”
  2. “yield”self.json_fetch的结果,而不是直接使用结果。
  3. 无需在协程中调用“finish”,Tornado在协程完成时完成响应。
  4. 也在“coroutine”中包装json_fetch。
  5. 结果:

    class ClubCreateActivity(tornado.web.RequestHandler):
    
        @tornado.gen.coroutine
        def post(self, *args, **kwargs):
            url = self.get_argument('url', None)
            response = yield self.json_fetch('POST', url, self.request.body)
            self.write(response.body)
    
        @tornado.gen.coroutine
        def json_fetch(self, method, url, body=None, *args, **kwargs):
            client = tornado.httpclient.AsyncHTTPClient()
            headers = tornado.httputil.HTTPHeaders({"content-type": "application/json charset=utf-8"})
            request = tornado.httpclient.HTTPRequest(url, method, headers, body)
            response = yield client.fetch(request)
            raise gen.Return(response)
    

    进一步阅读:

答案 1 :(得分:1)

龙卷风官方文档中推荐的方法是同时使用 @ tornado.gen.coroutine yield

如果要同时使用异步和yield的优势,则应嵌套 @ tornado.web.asynchronous 装饰器,然后嵌入 @ tornado.gen.engine

答案 2 :(得分:0)

有关“异步调用自己的函数”的文档,但没有额外的外部回调函数 - Asynchronous and non-Blocking I/O

您可以像这样制作 json_fetch

from tornado.concurrent import Future

def json_fetch(self, method, url, body=None, *args, **kwargs):
    http_client = tornado.httpclient.AsyncHTTPClient()
    my_future = Future()
    fetch_future = http_client.fetch(url)
    fetch_future.add_done_callback(
        lambda f: my_future.set_result(f.result()))
    return my_future

或者像这样(来自A. Jesse Jiryu Davis的回答):

from tornado import gen

@gen.coroutine
def json_fetch(self, method, url, body=None, *args, **kwargs):
    http_client = tornado.httpclient.AsyncHTTPClient()
    headers = tornado.httputil.HTTPHeaders({"content-type": "application/json charset=utf-8"})
    request = tornado.httpclient.HTTPRequest(url, method, headers, body)
    response = yield http_client.fetch(request)
    raise gen.Return(response)

*在json_fetch的“gen.coroutine”和“yield”调用中包装“post”。

**“仅为Python2提升gen.Return(响应)”,在Python3.3及更高版本中你应该写“返回响应”。

感谢A. Jesse Jiryu Davis提供链接“Tornado异步请求处理程序”,在那里找到了“异步和非阻塞I / O”。