Как использовать асинхронный API торнадо внутри tornado.wsgi.WSGIContainer?

Я пытаюсь использовать пользовательский WSGIContainer, который должен работать с асинхронными операциями:

from tornado import httpserver, httpclient, ioloop, wsgi, gen

@gen.coroutine
def try_to_download():
    response = yield httpclient.AsyncHTTPClient().fetch("http://www.stackru.com/")
    raise gen.Return(response.body)


def simple_app(environ, start_response):
    res = try_to_download()

    print 'done: ', res.done()
    print 'exec_info: ', res.exc_info()

    status = "200 OK"
    response_headers = [("Content-type", "text/html")]
    start_response(status, response_headers)
    return ['hello world']


container = wsgi.WSGIContainer(simple_app)
http_server = httpserver.HTTPServer(container)
http_server.listen(8888)
ioloop.IOLoop.instance().start()

Но это не работа. Похоже, приложение не ждет результата функции try_to_download. Также код ниже не работает:

from tornado import httpserver, httpclient, ioloop, wsgi, gen


@gen.coroutine
def try_to_download():
    yield gen.Task(httpclient.AsyncHTTPClient().fetch, "http://www.stackru.com/")


def simple_app(environ, start_response):

    res = try_to_download()
    print 'done: ', res.done()
    print 'exec_info: ', res.exc_info()

    status = "200 OK"
    response_headers = [("Content-type", "text/html")]
    start_response(status, response_headers)
    return ['hello world']


container = wsgi.WSGIContainer(simple_app)
http_server = httpserver.HTTPServer(container)
http_server.listen(8888)
ioloop.IOLoop.instance().start()

У вас есть идеи, почему это не работает? Я использую версию Python 2.7.

PS Вы можете спросить меня, почему я не хочу использовать родной tornado.web.RequestHandler. Основная причина в том, что у меня есть пользовательская библиотека Python (WsgiDAV), которая создает интерфейс WSGI и позволяет писать собственные адаптеры, которые я хочу сделать асинхронными.

1 ответ

WSGI не работает с асинхронным.

В общем, для функции, ожидающей завершения сопрограммы Торнадо, сама функция должна быть сопрограммой и должна yield результат сопрограммы:

@gen.coroutine
def caller():
    res = yield try_to_download()

Но, конечно, функция WSGI, как simple_app не может быть сопрограммой, потому что WSGI не понимает сопрограммы. Более подробное объяснение несовместимости между WSGI и async содержится в документации по Bottle.

Если вы должны поддерживать WSGI, не используйте AsyncHTTPClient от Tornado, вместо этого используйте синхронный клиент, такой как стандартный urllib2 или PyCurl. Если вы должны использовать AsyncHTTPClient Tornado, не используйте WSGI.

Другие вопросы по тегам