2014-01-30 3 views
1

Я пытаюсь использовать пользовательские WSGIContainer, который должен работать с асинхронными операциями:Как использовать API асинхронного торнадо внутри tornado.wsgi.WSGIContainer?

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

@gen.coroutine 
def try_to_download(): 
    response = yield httpclient.AsyncHTTPClient().fetch("http://www.stackoverflow.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.stackoverflow.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.

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

ответ

4

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

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

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

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

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

+0

Спасибо за ответ. Кажется, вы правы. Но в настоящее время я не знаю, почему такая функция, как WSGIContainer, может использоваться в приложении торнадо, если она не может работать с асинхронным API программирования торнадо. Таким образом, он блокирует основное приложение. – Dmitry

+3

Вы можете использовать WSGIContainer, если приложение WSGI, которое вы используете, достаточно быстро, чтобы не блокировать цикл событий. Это особенно полезно, когда есть преимущество в использовании WSGI-приложения в том же процессе, что и приложение Tornado. Я использую WSGIContainer для подключения Dowser к моим приложениям Tornado для обнаружения утечек памяти, например. –

Смежные вопросы