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)    收藏  举报

导航