2

我尝试使用应该与异步操作一起使用的自定义 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。

PS 你可能会问我为什么不想使用原生tornado.web.RequestHandler。主要原因是我有自定义 python 库(WsgiDAV),它产生 WSGI 接口并允许编写自定义适配器,我可以使它们异步。

4

1 回答 1

4

WSGI 不适用于异步。

一般来说,对于等待 Tornado 协程完成的函数,函数本身必须是协程并且必须yield是协程的结果:

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

但是当然像 WSGI 这样的函数simple_app不能是协程,因为 WSGI 不理解协程。在Bottle 文档中对 WSGI 和 async 之间的不兼容进行了更彻底的解释。

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

于 2014-01-30T15:23:57.610 回答