问题
I am trying to write a non-blocking api with tornado. But when I try it on local the first request is blocking the API. I tried to use different browsers but the result is same.
I opened chrome and firefox. On chrome I go http://localhost:8888/test-first and while it is loading I immediatly go http://localhost:8888/test-second from firefox.
I am expecting the request from firefox would be answered while the other one is still loading. But both of them are waiting and when the first request is done both of them finishes.
My codes and output:
Expecting console output:
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
Console Output
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()
回答1:
for _ in range(1000000000):
pass
This is a CPU intensive task. So, it blocks the whole server. Tornado, and almost every other async library, is for doing asynchronous network I/O, which means, data comes in, data goes out - no heavy CPU tasks.
To perform a CPU bound blocking task, you'll have to run it in a separate process, or thread so that it doesn't block the server.
But anyway, to get the output as you expect, you can pause the First
handler using tornado.gen.sleep
.
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)
...
来源:https://stackoverflow.com/questions/47442700/tornado-doesnt-work-asynchronously