2014-01-30 54 views
1

我尝试使用自定义WSGIContainer应与异步操作的工作:如何在tornado.wsgi.WSGIContainer中使用异步龙卷风API?

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不适用于异步。

在一般情况下,一个函数等待龙卷风协程来完成,函数本身必须是一个协程,必须yield协程的结果:

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

但当然像simple_app一个WSGI功能不能一个协程,因为WSGI不理解协程。有关WSGI和异步之间不兼容的更全面的解释请参见Bottle documentation

如果您必须支持WSGI,请勿使用Tornado的AsyncHTTPClient,请使用类似标准urllib2或PyCurl的同步客户端。如果您必须使用Tornado的AsyncHTTPClient,请不要使用WSGI。

+0

感谢您的回答。看起来你是对的。但是现在我不知道为什么WSGIContainer这样的功能可能在龙卷风应用程序中使用,如果它不能与龙卷风异步编程API一起使用的话。所以它阻止了主应用程序。 – Dmitry

+3

只要您使用的WSGI应用程序速度足够快,您就可以不介意阻止事件循环,您就可以使用WSGIContainer。当将WSGI应用程序与Tornado应用程序放在同一进程中有一些好处时,它非常有用 - 例如,我使用WSGIContainer将Dowser插入我的Tornado应用程序中以检测内存泄漏。 –