python tornado异步客户端提取调用回调失败了一些时间

时间:2015-03-11 15:14:50

标签: php python asynchronous tornado

当我请求使用Tornado异步调用的页面时,它有时会成功获取页面内容,但有时它将无法从本地服务器获取内容。

没有意义如何处理回叫。

在我的本地LAMP服务器上我有这个代码每页保持1秒。 // b.php

    <?php
    header( 'Content-type: text/html; charset=utf-8' );
    ob_implicit_flush();
    foreach (range(1,3) as $x){
      echo $x;
      usleep(333333);
    }
    ?>

// c.php

    <?php
    header( 'Content-type: text/html; charset=utf-8' );
    ob_implicit_flush();
    foreach (range(4,6) as $x){
      echo $x;
      usleep(333333);
    }
    ?>

// d.php

    <?php
    header( 'Content-type: text/html; charset=utf-8' );
    ob_implicit_flush();
    foreach (range(7,9) as $x){
      echo $x;
      usleep(333333);
    }
    ?>

在python web客户端/服务器上

我关注的代码。

我的回答为什么它不起作用,最后一次调用在第一次调用之前返回。因此它将完成回调并且无法执行其他回调以在屏幕上写入它但它应该触发所有请求并收集响应然后应该完成。任何想法? 如果可能,我如何修改此代码样式而不是使用yield

    import tornado.httpserver
    import tornado.ioloop
    import tornado.options
    import tornado.web
    import tornado.httpclient
    from tornado.options import define, options
    import tornado.gen

    define("port", default=8000, help="run on the given port", type=int)
    class IndexHandler(tornado.web.RequestHandler):
        @tornado.web.asynchronous
        @tornado.gen.engine
        def get(self):
            client = tornado.httpclient.AsyncHTTPClient()
            client.fetch("http://www.droid-life.com/?" + \
                         urllib.urlencode({"s": query}), callback=self.on_response)
            client.fetch("http://localhost/b.php", callback=self.on_response)
            client.fetch("http://localhost/c.php", callback=self.on_response)
            client.fetch("http://localhost/d.php", callback=self.on_response3)
        @tornado.web.asynchronous
        def on_response(self, response):
            body = (response.body)
            self.write(body)
        @tornado.web.asynchronous
        def on_response2(self, response):
            body = (response.body)
            self.write(body)
            client = tornado.httpclient.AsyncHTTPClient()
            client.fetch("http://localhost/d.php", callback=self.on_response3)
        def on_response3(self, response):
            body = (response.body)
            self.write(body)
            self.finish()
    if __name__ == "__main__":
        tornado.options.parse_command_line()
        app = tornado.web.Application(handlers=[(r"/", IndexHandler)])
        http_server = tornado.httpserver.HTTPServer(app)
        http_server.listen(options.port)
        tornado.ioloop.IOLoop.instance().start()

此代码实际上有效,并在1.1~1.3秒的合理时间内返回结果

    define("port", default=8000, help="run on the given port", type=int)
    class IndexHandler(tornado.web.RequestHandler):
        @tornado.web.asynchronous
        @tornado.gen.engine
        def get(self):

            client = tornado.httpclient.AsyncHTTPClient()
            r1,r2,r3 = yield [client.fetch("http://localhost/b.php"), \
                           client.fetch("http://localhost/c.php"), \
                           client.fetch("http://localhost/d.php") \
                            ]
            self.write(r1.body)
            self.write(r2.body)
            self.write(r3.body)
            self.finish()
    if __name__ == "__main__":
        tornado.options.parse_command_line()
        app = tornado.web.Application(handlers=[(r"/", IndexHandler)])
        http_server = tornado.httpserver.HTTPServer(app)
        http_server.listen(options.port)
        tornado.ioloop.IOLoop.instance().start()

1 个答案:

答案 0 :(得分:1)

你的问题不清楚事情究竟是如何失败的(以及为什么第二个版本既短又有效又不是一个可接受的解决方案),但有一件事我看到你的代码的第一个版本调用了on_response3(这两次调用完成):一次来自get(),一次来自on_response2。一旦调用了on_response3,您的处理程序就会停止,通过首先完成的代码路径。

如果要在回调样式中并行执行三次提取,则必须保留未完成提取次数的计数器,以便只有在完成所有三次提取后才能调用完成。第二个示例的基于回调的等价物将是这样的:

class IndexHandler(RequestHandler):
    @asynchronous
    def get(self):
        client = tornado.httpclient.AsyncHTTPClient()
        self.remaining = 3
        self.responses = {}
        client.fetch("http://localhost/b.php", functools.partial(self.on_response, 'b'))
        client.fetch("http://localhost/c.php", functools.partial(self.on_response, 'c'))
        client.fetch("http://localhost/d.php", functools.partial(self.on_response, 'd'))

    def on_response(self, key, response):
        self.responses[key] = response
        self.remaining -= 1
        if self.remaining == 0:
            self.write(self.responses['b'].body)
            self.write(self.responses['c'].body)
            self.write(self.responses['d'].body)
            self.finish()