Tornado 不能异步工作

Tornado doesn't work asynchronously

我正在尝试使用 tornado 编写非阻塞 api。但是当我在本地尝试时,第一个请求阻止了 API。我尝试使用不同的浏览器,但结果是一样的。

我打开了 chrome 和 firefox。在 chrome 我从 firefox 转到 http://localhost:8888/test-first and while it is loading I immediatly go http://localhost:8888/test-second

我期待来自 firefox 的请求在另一个仍在加载时得到答复。但是他们都在等待,当第一个请求完成时,他们都完成了。

我的代码和输出:

期望控制台输出:

First request: 2017-11-22 22:23:22.093497
Second request: 2017-11-22 22:23:24.580052
Second answer: 2017-11-22 22:23:25.580509
First answer: 2017-11-22 22:23:37.579263

控制台输出

First request: 2017-11-22 22:23:22.093497
First answer: 2017-11-22 22:23:37.579263
Second request: 2017-11-22 22:23:37.580052
Second answer: 2017-11-22 22:23:37.580509

test_first.py:

import tornado.web
import datetime


class First(tornado.web.RequestHandler):
    @tornado.web.asynchronous
    async def get(self):
        print("First request: " + str(datetime.datetime.now()))
        for _ in range(1000000000):
            pass
        self.set_status(200)
        self.write("OK")
        self.finish()
        print("First answer: " + str(datetime.datetime.now()))

test_second.py:

import tornado.web
import datetime


class Second(tornado.web.RequestHandler):
    @tornado.web.asynchronous
    async def get(self):
        print("Second request: " + str(datetime.datetime.now()))
        self.set_status(200)
        self.write("OK")
        self.finish()
        print("Second answer: " + str(datetime.datetime.now()))

app.py:

import tornado
from test_first import First
from test_second import Second


class Application(tornado.web.Application):
    def __init__(self):
        ENDPOINTS = [
            # USERS #
            (r"/test-first", First),
            (r"/test-second", Second)
        ]

        SETTINGS = {
            "debug": True,
            "autoreload": True,
            "serve_traceback": True,
            "compress_response": True
        }

        tornado.web.Application.__init__(self, ENDPOINTS, SETTINGS)


if __name__ == "__main__":
    print("dinliyor...")
    Application().listen(8888)
    tornado.ioloop.IOLoop.instance().start()
for _ in range(1000000000):
        pass

这是一项 CPU 密集型任务。因此,它会阻止整个服务器。 Tornado 和几乎所有其他异步库都用于执行异步网络 I/O,这意味着,数据进来,数据出去——没有繁重的 CPU 任务。

要执行 CPU 绑定阻塞任务,您必须 运行 在单独的进程或线程中执行它,这样它就不会阻塞服务器。

但无论如何,要获得预期的输出,您可以使用 tornado.gen.sleep.

暂停 First 处理程序
class First(tornado.web.RequestHandler):
    @tornado.web.asynchronous
    async def get(self):
        print("First request: " + str(datetime.datetime.now()))

        await tornado.gen.sleep(5) # sleep for 5 seconds

        self.set_status(200)
        ...