Tornado并发处理机制及多请求场景下的CPU状态疑问
问题与解答:Tornado多进程下慢IO请求的处理情况
我们有一个基于Tornado的Web应用,通过fork 4个子进程运行,核心代码如下:
主进程启动代码:
async def post_fork_main(): app = tornado.web.Application([(r'/', MyHandler)]) server = tornado.httpserver.HTTPServer(app) server.add_sockets(sockets) await asyncio.Event().wait() if __name__ == '__main__': sockets = tornado.netutil.bind_sockets(8080) tornado.process.fork_processes(4) print("Service is started successfully ...") asyncio.run(post_fork_main())
请求处理Handler代码:
class MyHandler(tornado.web.RequestHandler): async def get(self): # some other processing code. await call_api() # reply very slowly. # some other processing code. self.write('OK')
疑问
当4个子进程都处于等待call_api()(响应极慢)返回的状态时,如果请求数超过4个,会发生什么?此时CPU是否近乎空闲?
回答
1. 请求超过4个时的处理逻辑
- Tornado的每个子进程基于异步IO模型工作,单个子进程可以同时处理多个请求:当某个请求执行到
await call_api()时,对应的协程会被挂起,子进程的事件循环会立刻去处理队列中其他等待的请求,不会被这个慢IO操作阻塞。 - 新来的请求会先被操作系统的TCP监听队列(backlog)暂存,只要队列没满,请求就不会丢失;当某个子进程的事件循环有空(比如某个
call_api()完成,协程执行完毕),就会从队列中取出新请求进行处理。 - 如果请求量持续超过TCP队列的承载上限,后续的请求会被操作系统直接拒绝,客户端会收到类似
Connection Refused的错误。
2. CPU使用状态
- 此时CPU会近乎空闲。因为所有子进程的事件循环在等待IO完成时,挂起的协程不会占用CPU时间片——
await关键字会让事件循环释放CPU资源,直到call_api()的IO操作完成、协程被唤醒后,才会短暂占用CPU执行后续代码(比如self.write('OK'))。大部分时间里CPU处于等待IO响应的空闲状态。
内容的提问来源于stack exchange,提问作者taichi_tiger
相关产品推荐
相关产品推荐

