Python торнадо асинхронный клиент выборки вызов с обратным вызовом не удается несколько раз

Когда я запрашиваю страницы с вызовом Tornado Async, иногда он успешно получает содержимое страницы, но иногда он не может получить содержимое с моего локального сервера.

Не имеет смысла, как обрабатывается обратный звонок.

на моем локальном сервере 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);
}
?>

на питоне веб-клиент / сервер

Мой ответ, почему это не сработает: последний звонок возвращается раньше, чем первый. Таким образом, он завершит обратный вызов и не сможет выполнить другой обратный вызов, чтобы записать его на экране, но он должен запустить весь запрос и собрать ответ, а затем завершить. есть мысли?
Если это возможно, как я могу изменить этот стиль кода для работы вместо использования 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()

0

Решение

Ваш вопрос неясен относительно того, как именно происходит сбой (и почему вторая версия, которая и короче, и работает, не является приемлемым решением), но я вижу одно, что первая версия вашего кода вызывает 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()
1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]