2014-01-30 80 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應用程序中以檢測內存泄漏。 –