Python AsyncHTTPClient接收数据块时的Tornado流式HTTP响应

Python AsyncHTTPClient接收数据块时的Tornado流式HTTP响应,python,asynchronous,tornado,Python,Asynchronous,Tornado,我正在尝试编写一个Tornado请求处理程序,它生成异步HTTP请求,并在客户端从异步请求接收数据时将数据返回给客户端。不幸的是,在Tornado的所有异步HttpRequest完成之前,我无法让Tornado将任何数据返回到客户端 下面是我的请求处理程序的演示 class StreamingHandler(web.RequestHandler): all_requested = False requests = [] @web.asynchronous de

我正在尝试编写一个Tornado请求处理程序,它生成异步HTTP请求,并在客户端从异步请求接收数据时将数据返回给客户端。不幸的是,在Tornado的所有异步HttpRequest完成之前,我无法让Tornado将任何数据返回到客户端

下面是我的请求处理程序的演示

class StreamingHandler(web.RequestHandler): all_requested = False requests = [] @web.asynchronous def get(self): http_client = httpclient.AsyncHTTPClient() self.write('some opening') big_request = httpclient.HTTPRequest(url='[some_big_request]', streaming_callback=self.on_chunk) small_request = httpclient.HTTPRequest(url='[some_small_request]', streaming_callback=self.on_chunk) self.requests.append(http_client.fetch(big_request, callback=self.on_response_complete)) self.requests.append(http_client.fetch(small_request, callback=self.on_response_complete)) self.all_requested = True def on_chunk(self, chunk): self.write('some chunk') self.flush() def on_response_complete(self, response): if self.all_requested and all(request.done() for request in self.requests): self.write('some closing') self.finish() 类StreamingHandler(web.RequestHandler): 请求的所有内容=错误 请求=[] @web.asynchronous def get(自我): http_client=httpclient.asynchtpclient() self.write('someopen') big_request=httpclient.HTTPRequest(url='[some_big_request]',streaming_callback=self.on_chunk) small_request=httpclient.HTTPRequest(url='[some_small_request]',streaming_callback=self.on_chunk) self.requests.append(http\u client.fetch(big\u请求,callback=self.on\u响应完成)) self.requests.append(http\u client.fetch(小请求,回调=self.on\u响应完成)) self.all_requested=True 块上的def(自身,块): self.write('some chunk') self.flush() def on_响应_完成(自我,响应): 如果self.all_已请求且self.requests中的请求为all(request.done()): self.write('someclosing') self.finish() 我希望对这个处理程序的GET请求最初返回文本“some opening”,然后很快为小请求返回“some chunk”,然后为大请求返回“some chunk”(可能多次),最后返回“some closing”,并关闭连接。相反,在建立连接之后,客户端会等待几秒钟,等待所有请求完成,然后在关闭之前立即接收所有HTTPResponse

我将如何从龙卷风中获得我想要的行为


提前谢谢

gen.coroutine
装饰您的方法,并生成一个未来列表。下面是一个简单的例子:

from tornado import gen, web, httpclient

class StreamingHandler(web.RequestHandler):
    @web.asynchronous
    @gen.coroutine
    def get(self):
        client = httpclient.AsyncHTTPClient()

        self.write('some opening')
        self.flush()

        requests = [
            httpclient.HTTPRequest(
                url='http://httpbin.org/delay/' + str(delay),
                streaming_callback=self.on_chunk
            ) for delay in [5, 4, 3, 2, 1]
        ]

        # `map()` doesn't return a list in Python 3
        yield list(map(client.fetch, requests))

        self.write('some closing')
        self.finish()

    def on_chunk(self, chunk):
        self.write('some chunk')
        self.flush()

请注意,即使请求是“向后”生成的,第一个块仍将在大约一秒钟后被接收。如果同步发送,需要15秒。当您异步请求它们时,只需5分钟。

您好,谢谢。不过有几个问题:你能解释一下为什么我的代码不起作用而你的代码起作用吗?这似乎是由于“屈服”在tornado.gen.coroutine中的神秘用法。你如何保证一旦你产生了一个未来列表,请求就完成了,并且写下“一些结束”是安全的?@majackson:这就是Tornado实现协同路由的方式。通过使用
yield
,您的函数将成为生成器,因此您可以在
yield
任务处有效地启动和停止它。当您
生成一个任务(或Tornado一次执行所有任务的任务列表)时,您告诉Tornado的iLoop它可以“停止”执行您的函数并执行其他操作。当它“返回”到您的函数时,它将从它停止的地方开始。您的函数代码仍将自上而下执行,但Tornado也将跳转到其他函数。这有点像Node.js的工作方式。