为何Tornado无法处理并发请求?如何实现多请求同时处理?
Tornado异步框架无法并发处理请求的原因及解决方法
嘿,这个问题我太熟了!你遇到的其实是Tornado里同步阻塞操作抢占IO循环的典型坑,咱们一步步拆解清楚:
为什么会出现请求排队?
先看你的代码:MainHandler里的do_something()用了input()——这是个同步阻塞调用,会直接把Tornado唯一的IO循环线程给卡死。
Tornado的异步是单线程模型,所有请求、事件监听全靠这一个IO循环线程驱动。如果某个操作阻塞了这个线程(比如等用户输入、time.sleep()、同步数据库查询),那后面的请求只能乖乖排队,直到阻塞操作结束。
你加的@tornado.web.asynchronous装饰器其实只是告诉Tornado:“别自动帮我调用finish(),我自己来”,它并没有把你的方法变成异步的——你的do_something()还是实打实的同步阻塞代码,所以整个IO循环被锁死,/hello请求自然得等它做完才能处理。
怎么实现并发处理?
核心思路就是绝对不能让IO循环线程被阻塞,把同步阻塞操作改成异步方式。针对你的场景,给你两种可行的修改方案:
方案1:用协程+异步任务包装阻塞操作
把阻塞的input()放到单独的回调里,让IO循环在等待的时候能处理其他请求:
import tornado.ioloop import tornado.web from tornado.gen import coroutine, Task class MainHandler(tornado.web.RequestHandler): @coroutine def get(self): yield self.do_something() self.write("FINISHED") self.finish() @coroutine def do_something(self): # 用Task把阻塞操作包装成异步任务,让出IO循环 yield Task(tornado.ioloop.IOLoop.current().add_callback, self._handle_input) def _handle_input(self): inp = input("enter to continue") print(inp) class HelloHandler(tornado.web.RequestHandler): def get(self): print("say hello") self.write("Hello bro") self.finish() # 你原代码这里少了个括号,先补上! def make_app(): return tornado.web.Application([ (r"/", MainHandler), (r"/hello", HelloHandler) ]) if __name__ == "__main__": app = make_app() app.listen(8888) tornado.ioloop.IOLoop.current().start()
方案2:用线程池处理阻塞操作
如果是实际业务里的重型阻塞操作(比如同步调用第三方API),可以用Tornado的ThreadPoolExecutor把操作放到线程池里,不占用IO循环线程:
import tornado.ioloop import tornado.web from tornado.gen import coroutine from concurrent.futures import ThreadPoolExecutor executor = ThreadPoolExecutor(2) class MainHandler(tornado.web.RequestHandler): @coroutine def get(self): yield self.do_something() self.write("FINISHED") self.finish() @coroutine def do_something(self): # 把阻塞操作提交到线程池 inp = yield executor.submit(input, "enter to continue") print(inp) # HelloHandler和make_app部分和上面一致
关键知识点再强调
- Tornado是单线程异步框架,IO循环是核心,绝对不能让它被同步操作阻塞。
- 所有耗时IO操作(数据库、HTTP请求、文件读写)都要用Tornado提供的异步客户端,或者用线程/进程池包装。
@tornado.web.asynchronous不是“魔法异步开关”,它只是控制finish()的调用时机,真正的异步要靠协程、回调或者线程池实现。
另外提一句:你原代码里HelloHandler的finish()少了个右括号,记得补上哦!
内容的提问来源于stack exchange,提问作者vinaykp
相关产品推荐
相关产品推荐

