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

Asynchronous 如何在Tornado中将异步函数和gen函数包装在一起?,asynchronous,generator,tornado,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.asy

如何在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)
在这个代码示例中,您不需要“异步”。“gen.engine”已过时,请使用“coroutine”。现在,您通常也不需要经常使用“gen.Task”。对代码进行四项更改:

  • 将“post”包装在“coroutine”中
  • “yield”self.json_fetch的结果,而不是直接使用结果
  • 在协同程序中不需要调用“finish”,Tornado在协同程序完成时完成响应
  • 也将json包装到“coroutine”中
  • 结果是:

    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)
    
    进一步阅读:


    tornado官方文件中推荐的方法是同时使用@tornado.gen.corroutineyield

    如果您想同时使用异步和收益率优势,您应该嵌套@tornado.web.asynchronous装饰器,然后嵌套@tornado.gen.engine

    关于“异步调用自己的函数”的文档,但不包含额外的外部回调函数-

    您可以按如下方式获取json\u:

    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的回答):

    *将“post”封装在“gen.coroutine”中,并对json_fetch进行“yield”调用

    **“raise gen.Return(response)”仅适用于Python2,在Python3.3及更高版本中,您应该编写“Return response”


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

    我去学习gen.coroutine的知识。似乎我必须这样写,因为我使用的是Python 2?raise gen.Return(response.body)我如上所述尝试过:AttributeError:'NoneType'对象没有属性'body',为什么我仍然需要在函数post中使用yiled?json_fetch已经返回了一个future对象?是的,json_fetch返回一个future。为了等待将来对响应进行解析,“post”函数必须让步。yield暂停“post”直到“json_fetch”完成,然后“post”以响应值继续。
    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)