tornado十四:tornado中的异步
tornado中的异步:epoll主要是用来解决网络io的并发问题,所以tornado的异步也是主要体现在网络的io异步上,即异步web请求。
一、tornaod同步请求
示例,两个客户端,一个请求students,一个请求home:
#Application.py
class Application(tornado.web.Application): def __init__(self): handlers = [ ('r/home', index.HomeHandler), ('r/sutdents', index.StudentsHandler), ] super(Application, self).__init__(self, handlers, **config.settings)
#index.py
class StudentsHandler(RequestHandler): def get(self, *args, **kwargs): time.sleep(20) self.write('ok')
class HomeHandler(RequestHandler): def get(self, *args, **kwargs): self.write(u'这是home视图函数')
# server.py
import tornado.ioloop import tornado.httpserver import tornadoConfig from Application import Application if __name__ == '__main__': app = Application() httpServer = tornado.httpserver.HTTPServer(app) httpServer.bind(tornadoConfig.options["port"]) httpServer.start(1) tornado.ioloop.IOLoop().current().start()
# tornadoConfig.py
# tornaod配置 settings = { } # 数据库配置 mysql = { "host": "127.0.0.1", } # 服务器配置 options = { "port": 9000, }
模拟:先在一个浏览器访问students,再另一个浏览器访问home。
结果:home页面,要等待students请求完成后,再回返回。
说明此时tornado是同步请求和响应的。
在请求示例中:当studentsHandler向数据库去拿取数据时,studentsHandler相对于数据库,就是客户端,数据库是服务器。
这也是网络io请求。需要使用:1.异步web请求客户端和2.回调方法。
怎么使用tornado中的异步响应?
1.创建异步web请求客户端client:使用tornado提供的tornado.httpclient.AsyncHTTPClient异步web请求客户端,用来进行异步 web请求。
2.调用异步web请求客户端client的fetch()方法返回一个异步响应response:
fetch(request, callback=None),用于执行一个web请求,并异步响应返回一个tornado.httpclient.HttpResponse。
- 当callback,传递回调函数时,使用的是回调函数的方式实现异步;
- 当callback为None时,使用的是协程的方式实现异步。
- request:可以是一个url,也可以是一个tornado.httpclient.HttpRequest对象。当传的是url时,会自动创建一个HttpRequest对象
使用上面的方法,即可实现tornado中的步异响应。
由fetch方法中,是否有callback对象,决定了有两种方式实现异步响应:异步回调函数和协程实现异步两种方式
二、fetch()方法的参数和返回值:
HTTPRequest请求类:是HTTP请求类,该类的构造函数可以接收参数。
使用该类,创建HTTPRequest对象。
fetch(request, callback=None)方法中的request对象,就是此HTTP请求类的实例。
HTTP请求类的参数:
-
- url,字符串类型,要访问的网址,必传
- method:字符串类型,HTTP请求方式
- headers:字典类型,或者HTTPHeaders类型。附加的协议头。
- body:HTTP请求体,用于post请求。
HTTPResponse响应类:是HTTP响应类,它有一些属性。
fetch(request, callback=None)方法中的返回的response对象,就是此HTTP响应类的实例。
我们要返回客户端的数据,就在此HTTP响应对象的属性中。
HTTP响应类的一些属性:
-
- code:状态码
- reason:状态码的描述
- body:响应的数据
- error:异常信息
三、用回调函数的方式实现tornado中的异步
1.创建异步web请求客户端:client = tornado.httpclient.AsyncHTTPClient()
2.调用客户端的fetch(request, callback=None)方法:执行回调函数,并挂起客户端请求,交出请求处理通道。
3. 重写回调函数self.on_respone(),在回调函数中返回数据self.write(data)。
但是,回调函数返回的数据,并没有响应到客户端?为什么?
因为回调函数实现的异步,不能使用res接收返回数据;需要在回调函数中返回数据(不能是return),这里使用self.write(data)。但是get请求已结束,连接通道已关闭,因此客户端接收不到数据。
4.不关闭连接的通讯通道的装饰器:tornado.web.asynchronous。因为我们要等回调函数执行,并等回调函数写入返回的数据,才能关闭通道。
5.处理回调函数返回的数据response:jason.loads(response.body)
6.回调完成后,返回数据给客户端:self.write(),且执行self.finish()关闭通道
注意:执行self.finish()将自动关闭通道,后面再写入的数据不能返回客户端;执行self.write()并不会关闭通道,后面再写入的数据,一起返回客户端。
import json from tornado.httpclient import AsyncHTTPClient from tornado.web import RequestHandler class StudentsHandler(RequestHandler): def on_response(self, response): # 4.返回数据 if response.error: self.send_error(500) else: data = json.load(response.body) self.write(data) # 5.关闭通讯通道 self.finish()
@tornado.web.asynchrouous def get(self, *args, **kwargs): url = "http://www.baidu.com" # 1.创建异步web请求客户端 client = AsyncHTTPClient() # 2.发起回调函数请求:挂起交出请求通道,并异步返回数据 # longIo(callback) client.fetch(url, self.on_response) self.write('ok')
四、用协程实现tornado中的异步
1.创建异步web请求客户端:client = tornado.httpclient.AsyncHTTPClient()
2.调用客户端的fetch(request)方法:返回生成器res,并挂起客户端请求,交出请求处理通道。执行request中的请求。
3.使用协程异步装饰器,@tornaodo.gen.coroutine:装饰请求方法。
4. 处理res返回的数据response:jason.loads(response.body)
5.返回数据给客户端:self.write()
可见,协程实现的异步,同回调函数实现的异步的区别:
相同之处:都不可以使用return返回数据;
不同之处:请求方法中,无法以任何形式接收到回调函数返回的数据,但可以接收到协程实现的异步send回来的数据
不同之处:回调函数没有任何办法返回数据,只能直接使用self.write(data)将数据写入缓存;而协程实现的异步使用生成器的send(data)方法可以返回数据,然后再使用self.write(data)将数据写入缓存。
相同之处:都在装饰器中,另起了一个线程,将耗时操作挂起,让出请求通道,实现异步响应。
不同之处:回调函数使用@tornado.web.asynchrouous装饰器,目的是不关闭通讯通道,让回调函数写入的数据,可以返回给客户端。协程实现的异步,不需要此装饰器,因为它可以接收到异步返回的数据res,在请求方法中,即可返回耗时操作所挂起的异步数据。但是协程实现的异步,需要@tornado.gen.coroutine装饰器,目的是为了处理了生成器对象gen,使得请求方法得到的生成器,在耗时操作中可以调用其send方法返回耗时操作要返回的数据,而不需要使用全局变量。
import json from tornado.httpclient import AsyncHTTPClient from tornado.web import RequestHandler class Students2Handler(RequestHandler): @tornado.gen.corcoutine def get(self, *args, **kwargs): url = "http://www.baidu.com" # 1.创建异步web请求客户端 client = AsyncHTTPClient() # 2.发起协程异步响应:挂起、交出请求通道,并在此接收异步返回的数据 # res = yield longIo() res = yield client.fetch(url)
# 3.返回数据 if res.error: self.send_error(500) else: data = json.load(res.body) self.write(data)
五、优化协程实现tornado中的异步:将耗时loginIo从HTTP请求方法中独立出来,两个方法都要加gen装饰器
class Students3Handler(RequestHandler): @tornado.gen.corcoutine def get(self, *args, **kwargs): res = yield self.getData() self.write(res)
@tornado.gen.corcoutine # 这里也要使用异步装饰器 def getData(self): # 将耗时操作分离到此处 url = "http://www.baidu.com" client = AsyncHTTPClient() res = yield client.fetch(url) if res.error: ret = {"ret": 0} else: ret = {"ret": json.load(res.body)} # 返回数据,这里不能使用return,要使用生成器的send方法,在tornado中是: raise tornado.gen.Return(ret)
异步mysql示图:
posted on 2018-08-11 15:33 myworldworld 阅读(689) 评论(0) 收藏 举报