tornado 11 异步编程
一、同步与异步
同步
#含义:指两个或两个以上随时间变化的量在变化过程中保持一定的相对关系 #现象:有一个共同的时钟,按来的顺序一个一个处理 #直观感受:需要等待,效率低下
异步
#含义:双方不需要共同的时钟,就是接收方不知道发送方什么时候发送,所以在发送的信息中就要有提示接收方开始接受的信息,如开始位,同时在结束时有结束位 #现象:没有共同的时钟,不考虑顺序来了就处理 #直观感受:不需要等待,效率高
二、阻塞与非阻塞
阻塞调用
#含义:阻塞调用是指在调用结果返回之前,当前线程会被挂起(线程进入非可执行状态,在这个状态下,CPU不会给线程分配时间片,即线程暂停运行)。函数只有在得到结果之后才会返回 #现象:读套接字是没用数据等数据来,写套接字时写不下了也一直等,等能写下了往下写(套接字被写满的原因不在本地,在于网络另一头的套接字被写满了来不及读出去,导致本地的套接字内容发不出来,堵住了) #直观感受:执着
非阻塞调用
#含义:非阻塞调用是指没有调用结果立即返回,当前线程不被挂起,可以继续做其他工作 #现象:读套接字是没有数据,不等直接返回干别得事情去了,写套接字写不下了也不写了,直接返回干别的事情去了 #直观感受:勤奋
三、异步编程
#tornado是单线程的,一次只能处理一个请求;但是由于他是异步的,所以是高并发的 #那么在tornado中,同时有多个请求发送过来时,而且其中还有请求发生阻塞,会产生什么样的后果呢?
#在实现第四种异步方法的时候需要导入两个模块 futures requests
import time import tornado.ioloop import tornado.options import tornado.web from tornado.options import define,options from tornado.web import authenticated import tornado.websocket import tornado.httpclient import tornado.gen from tornado.concurrent import run_on_executor from concurrent.futures import ThreadPoolExecutor import requests import util.ui_methods import util.ui_modules from data.user_modules import User #导入module包 from pycket.session import SessionMixin import datetime define('port',default=8080,help = 'run port',type=int) class BaseHandler(tornado.web.RequestHandler,SessionMixin): def get_current_user(self): current_user = self.session.get('user') if current_user: return current_user return None class AbcHandler(BaseHandler): def get(self): self.write('abc ok') class SyncHandler(BaseHandler): def get(self): client = tornado.httpclient.HTTPClient() response = client.fetch('http://127.0.0.1:8080/sync?id=2') #这是模拟阻塞的接口,该接口代码里面有sleep用来模拟阻塞 print(response) self.write(response.body) #1、通过回调函数实现异步 class CallbcakHandler(BaseHandler): #这便是异步的方法,在阻塞的时候就直接处理其他的请求 @tornado.web.asynchronous #必须得装上装饰器 def get(self): client = tornado.httpclient.AsyncHTTPClient() response = client.fetch('http://127.0.0.1:8080/sync?id=2',callback=self.on_response) #当这个地方发生阻塞时,并没有在这个地方等待,而是后面的全部处理完了才来处理这个 self.write('ok') #这便是通过回调函数实现异步,先出现ok,在回到上面 def on_response(self,res): print(res) self.write(res.body) self.finish() #在这个回调函数中必须加上finish,不加上的话就会不知道上面的接口函数什么时候结束 #2、通过协程实现异步 class GenHandler(BaseHandler): @tornado.web.asynchronous @tornado.gen.coroutine #协程 def get(self): client = tornado.httpclient.AsyncHTTPClient() response = yield tornado.gen.Task(client.fetch,'http://127.0.0.1:8080/sync?id=2') #yield生成器,有等待、暂停的功能 self.write(response.body) #3、通过协程实现异步(自定义函数) 更加灵活 class FuncHandler(BaseHandler): @tornado.web.asynchronous @tornado.gen.coroutine #协程 def get(self): response = yield self.func() self.write(response.body) @tornado.gen.coroutine def func(self): client = tornado.httpclient.AsyncHTTPClient() response = yield tornado.gen.Task(client.fetch, 'http://127.0.0.1:8080/sync?id=2') # yield生成器,有等待、暂停的功能 raise tornado.gen.Return(response) #4、通过requests包来实现异步,都是使用装饰器 class MyHandler(BaseHandler): executor = ThreadPoolExecutor() @tornado.web.asynchronous @tornado.gen.coroutine def get(self): response = yield self.func() self.write(response.text) @run_on_executor def func(self): res = requests.get('http://127.0.0.1:8080/sync?id=2') return res application = tornado.web.Application( handlers=[ (r'/abc',AbcHandler), (r'/sync', SyncHandler), (r'/call', CallbcakHandler), (r'/gen', GenHandler), (r'/func', FuncHandler), (r'/my', MyHandler), ], template_path = 'templates', static_path= 'static', autoescape = None, ui_methods=util.ui_methods, ui_modules=util.ui_modules, cookie_secret = 'lidang', login_url = '/login', pycket = { 'engine':'redis', 'storage':{ 'host':'localhost', 'port':6379, 'db_sessions':5, 'db_notifications':11, 'max_connections':2 ** 33, }, 'cookie':{ 'expires_days':38, 'max_age':100 } }, debug=True ) if __name__ == '__main__': tornado.options.parse_command_line() http_server = tornado.httpserver.HTTPServer(application) http_server.listen(options.port) tornado.ioloop.IOLoop.instance().start()