Tornado 是什么?
Tornado 是一个 Python 写的:高性能异步 Web 服务器 + Web 框架
它最核心的特点:异步、非阻塞、高并发、长连接、极快
1. 一句话定位
你可以把它理解成:Python 里专门用来做「高并发 API 服务」的轻量级 Web 服务器
和 Flask、Django 最大区别:
- Flask/Django:同步、适合普通网站、接口
- Tornado :异步、非阻塞、适合高并发、长连接、AI 推理服务
vLLM、TGI、FastChat 等大模型推理服务 底层都用 Tornado 做 API 服务器!
vLLM 启动的 OpenAI-compatible server,背后就是 Tornado。
2. Tornado 最牛的地方(为什么大模型都用它)
- 高并发 单进程就能扛 成千上万连接,不卡不死
- 非阻塞 I/O等待模型推理时,不会卡住其他请求
- 长连接支持SSE / WebSocket 都很稳
- 轻量比 Django 轻太多,专门做 API 网关
3. 最简单可运行代码(一看就懂)
python
import tornado.ioloop
import tornado.web
# 定义 API 接口
class MainHandler(tornado.web.RequestHandler):
async def get(self):
self.write("Hello, Tornado 高性能服务!")
# 启动服务
def make_app():
return tornado.web.Application([(r"/", MainHandler)])
if __name__ == "__main__":
app = make_app()
app.listen(8888) # 监听端口
tornado.ioloop.IOLoop.current().start()
例2:
python
import tornado.ioloop
import tornado.web
import tornado.httpserver
from tornado import gen
from tornado.concurrent import run_on_executor, futures
# 定义 API 接口
class MainHandler(tornado.web.RequestHandler):
async def get(self):
self.write("Hello, Tornado 高性能服务!")
class BaseHandler(tornado.web.RequestHandler):
executor = None
def initialize(self):
# 在初始化时创建线程池
if BaseHandler.executor is None:
logger.info(f"创建线程池,当前活动线程数:{threading.active_count()}")
BaseHandler.executor = futures.ThreadPoolExecutor(max_workers=ducc_config["serving"]["default_thread_pool_size"])
def get(self):
html = """<p>服务已启动</p>"""
self.write(html)
@gen.coroutine
def post(self):
result = yield self._call_back()
self.write(json.dumps(result))
@run_on_executor
def _call_back(self):
pass
def set_default_headers(self):
origin_url = str(self.request.headers.get("Origin"))
self.set_header("Access-Control-Allow-Origin", origin_url)
self.set_header("Access-Control-Allow-Credentials", "true")
self.set_header("Access-Control-Allow-Headers", "x-requested-with,token")
self.set_header("Access-Control-Allow-Methods", "POST, GET, OPTIONS")
self.set_header("Access-Control-Max-Age", 1000)
class UrlCheckHandler(BaseHandler):
# 接口健康检查
def get(self):
post_ump_monitor(umpKey="aigent.interface.healthCheck", isSuccess="true", start_time=time.time(), requestId="url-check", ducc_config=ducc_config)
self.set_status(200)
self.write({"status": "OK"})
class informationExtractHandler(BaseHandler):
@run_on_executor
def _call_back(self):
try:
json_req = json.loads(self.request.body)
requestId = json_req.get("requestId", "")
erp = json_req.get("erp", "")
agent = json_req.get("agent", "")
logger.info(f"{requestId} informationExtractHandler 输入:{json_req}")
if os.path.exists(cfg.default_ducc_path):
ducc_conf = cfg.get_ducc_obj()
else:
ducc_conf = cfg.get_ducc_config()
result = information_extract(requestId, erp, ducc_conf, agent)
logger.info(f"{requestId} informationExtractHandler 返回:{result}")
return {"code": 200, "data": result}
except:
error_msg = traceback.format_exc().replace("\n", "\\n")
logger.error(error_msg)
return {"code": 500, "error": error_msg}
@gen.coroutine
def post(self):
result = yield self._call_back()
self.write(json.dumps(result, ensure_ascii=False))
class ChatHandler(BaseHandler):
@run_on_executor
def _call_back(self):
try:
jsonobj = self.request.body
json_req = json.loads(jsonobj)
logger.info(f"{json_req.get('requestId')} 接收到输入参数botChat:{json_req}")
if os.path.exists(cfg.default_ducc_path):
ducc_config = cfg.get_ducc_obj()
else:
ducc_config = cfg.get_ducc_config()
agent2strategy: dict = ducc_config["agent2strategy"]
def sync_process(json_req):
logger.warning(f"处理方法")
return result
if json_req.get("sync", False):
# 同步
result = sync_process(json_req)
return {"code": 200, "result": result}
else:
# 异步
thread = threading.Thread(target=sync_process, args=(json_req,))
thread.start()
return {"code": 200, "result": "1"}
except:
error_msg = traceback.format_exc().replace("\n", "\\n")
logger.error(error_msg)
return {"code": 500}
if __name__ == "__main__":
log_config()
if not cfg.is_debug:
thread = threading.Thread(target=update_ducc_config_sync, args=(cfg.default_ducc_path,))
thread.start()
logger.info("DUCC configs regularly update start.")
app = tornado.web.Application(
[
# openAI接口
(f"/openingDialog", OpeningDialogueHandler),
# 问答接口
(r"/botChat", ChatHandler)
],
autoreload=False,
debug=cfg.is_debug
)
http_server = tornado.httpserver.HTTPServer(app)
http_server.bind(cfg.port)
http_server.start(1)
logger.info(f"服务启动成功\n物理核数:{psutil.cpu_count(logical=False)}")
tornado.ioloop.IOLoop.instance().start()
4. 在LLM服务场景里Tornado 做什么?
架构:
用户请求 → Tornado (API 服务器) → vLLM → Qwen 模型 → 返回结果
Tornado 就是那个:接收 HTTP 请求 → 转发给模型 → 返回流式输出 的高性能网关。