tornado是一个异步非阻塞框架,对于高并发情况非常友好,本文教大家怎么实现tornado的异步,提升自己服务接口的吞吐率!
大多数新手可能对异步非阻塞不是很理解,现在详细讲解:
- 假设你的后端程序是单进程运行的,有两个用户同时请求,如果你处理a用户的事务时间比较长,那么b用户就得一直等待a用户处理完事务才能响应b用户。
- 出现上述情况通常是阻塞型任务,比如:数据库操作、复杂的计算、网络请求等
为了解决上述的问题,tornado框架自带协程的方法进行处理阻塞的事务
关于使用延迟函数
以下1和2采用协程的方式(@tornado.gen.coroutin),3采用回调函数的方式
- 如果tornado版本在4.1之后,不能使用time.sleep(),而是yield tornado.gen.sleep(),因为如果方法装饰协程的话,阻塞的事务调用也必须是协程的方式,所以不能用time.sleep()
class TestHandler(tornado.web.RequestHandler): @tornado.gen.coroutine def get(self): print('test') yield gen.sleep(10) self.write("sleep 10s")
- 如果tornado版本在3.0 ~ 4.1间,可以使用yield tornado.gen.Task(tornado.ioloop.IOLoop.instance().add_timeout, time.time() + 10)
class SleepHandler(tornado.web.RequestHandler): @tornado.web.asynchronous @tornado.gen.coroutine def get(self): yield tornado.gen.Task(tornado.ioloop.IOLoop.instance().add_timeout, time.time() + 5) self.write("sleep 10s")
- 如果tornado版本在3.0前,使用callback方式,非协程
# tornado3.0之前 class SleepHandler(tornado.web.RequestHandler): @tornado.web.asynchronous def get(self): tornado.ioloop.IOLoop.instance().add_timeout(time.time() + 5, callback=self.on_response) def on_response(self): self.write("sleep 5s") self.finish()
上述如果用浏览器测试相同的接口的话还是会出现等待A完成后再处理B的情况,这是因为浏览器的缘故,请求接口的时候加上不同的参数即可,如带上当前时间戳&_t=1354545680526
关于阻塞型事务
- 前面说过,用协程的方式的话,阻塞的语句需要使用阻塞库来操作,能不能使用常用的写法,答案是可以的,即通过线程的方式。
- 下述demo中,一共分为三步,1. 为这接口定义线程池的大小 2. 阻塞的事务函数加上@run_on_executor装饰器 3. 网络函数使用协程处理
from tornado.concurrent import run_on_executor from concurrent.futures import ThreadPoolExecutor class LogHandler(tornado.web.RequestHandler): # 1.线程池大小 executor = ThreadPoolExecutor(4) # 2.阻塞的函数上加@run_on_executor @run_on_executor def sleep(self, second): time.sleep(second) return second @gen.coroutine def get(self): # 3.yield来调用 # (没有返回也要yield) second = yield self.sleep(10) self.write('noBlocking Request: {}'.format(second))
关于tornado高并发的内容会持续在此文更新,接下来会添加网络io的处理!!!
下载仅供下载体验和测试学习,不得商用和正当使用。
下载体验