【问题标题】:Why does Tornado's WSGI support block for more than one request?为什么 Tornado 的 WSGI 支持阻止多个请求?
【发布时间】:2016-06-12 16:22:45
【问题描述】:

想象一下以下龙卷风应用:

import logging
import time

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


def simple_app(environ, start_response):
    time.sleep(1)
    status = "200 OK"
    response_headers = [("Content-type", "text/plain")]
    start_response(status, response_headers)
    return [b"Hello, WSGI world!\n"]

class HelloHandler(web.RequestHandler):
    @gen.coroutine
    def get(self):
        yield gen.moment
        self.write('Hello from tornado\n')
        self.finish()

def main():
    wsgi_app = wsgi.WSGIContainer(simple_app)
    tornado_app = web.Application(
        [
            ('/tornado', HelloHandler),
            ('.*', web.FallbackHandler, dict(fallback=wsgi_app)),
        ],
        debug=True,
    )
    http_server = httpserver.HTTPServer(tornado_app)
    http_server.listen(8888)
    current_loop = ioloop.IOLoop.current()
    current_loop.start()


if __name__ == '__main__':
    main()

现在,如果您运行此程序并尝试获取http://localhost:8888/ tornado 块,直到 WSGI 请求完成(这里是在一秒钟后休眠)。这件事我知道。但是,如果您一个接一个地发送许多请求,那么 IOLoop 可能会永远阻塞。

我尝试了这样的基准测试:

$ ab -n 20 -c 2 localhost:8888

在第二个终端中,我尝试获取另一个网址:

$ curl http://localhost:8888/tornado

直到所有其他并发 WSGI 请求完成后,我才收到非 WSGI 请求的响应。这仅在删除 yield gen.moment 时有效。

谁能解释这里发生了什么以及如何防止 Tornado 阻止我的所有请求,而不仅仅是其中一个?

【问题讨论】:

    标签: python-3.x tornado wsgi


    【解决方案1】:

    Tornado 的WSGIContainer 不是为高流量使用而设计的。查看its docs中的警告:

    WSGI 是一个同步接口,而 Tornado 的并发模型是基于单线程异步执行的。这意味着使用 Tornado 的 WSGIContainer 运行 WSGI 应用程序的可扩展性低于在多线程 WSGI 服务器(如 gunicorn 或 uwsgi)中运行相同的应用程序。仅当在同一进程中组合 Tornado 和 WSGI 的好处大于降低的可伸缩性时,才使用 WSGIContainer。

    一般来说,最好在单独的进程中运行 WSGI 和 Tornado 应用程序,这样 WSGI 部分就可以拥有一个专为 WSGI 设计的服务器。 WSGIContainer只有在有特定原因将它们组合在同一个进程中时才应该使用,然后应该小心使用,避免阻塞事件循环太久。最好尽可能在 Tornado-native RequestHandlers 中做,这样就可以使用协程而不是阻塞。

    【讨论】:

    • 非常感谢。我从结合 WSGI 和 Tornado 中获得了一些好处,所以我希望我可以通过稍后使用优先级队列来减轻阻塞问题,以便在一个阻塞 WSGI 调用 Tornado 运行 IOLoop 之后,每个人都有机会在它是下一个之前进入中间阻止轮到 WSGI 调用。但是,如果 Tornado 不运行 IOLoop,只要有 any 未完成的 WSGI 请求,这将不起作用。
    猜你喜欢
    • 1970-01-01
    • 2013-11-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-14
    • 2021-08-28
    • 2021-12-17
    相关资源
    最近更新 更多