阿里云-云小站(无限量代金券发放中)
【腾讯云】云服务器、云数据库、COS、CDN、短信等热卖云产品特惠抢购

Tornado异步

193次阅读
没有评论

共计 3259 个字符,预计需要花费 9 分钟才能阅读完成。

一、说明

因为 epoll 主要是用来解决网络 IO 的并发问题,所以 Tornado 的异步编程也主要体现在网络 IO 的异步上,即异步 Web 请求

二、Tornado 异步处理方法与类

  • tornado.httpclient.AsyncHTTPClient

    Tornado 提供了一个异步 Web 请求客户端 tornado.httpclient.AsyncHTTPClient 用来进行异步 Web 请求

  • fetch(request, callback=None)

    用于执行一个 web 请求 request,并异步返回一个 tornado.httpclient.HTTPResponse 响应

    request 可以是一个 url,也可以是一个 tornado.httpclient.HTTPRequest 对象。如果是 url,fetch 会自己构造一个 HTTPRequest 对象

  • HTTPRequest

    HTTP 请求类,HTTPRequest 的构造函数可以接收众多构造参数,最常用的如下

    • url(string) – 要访问的 url,此参数必传,除此之外均为可选参数
    • method (string) – HTTP 访问方式,如“GET”或“POST”,默认为 GET 方式
    • headers (HTTPHeaders or dict) – 附加的 HTTP 协议头
    • body – HTTP 请求的请求体
  • HTTPResponse

    HTTP 响应类,其常用属性如下:

    • code: HTTP 状态码,如 200 或 404
    • reason: 状态码描述信息
    • body: 响应体字符串
    • error: 异常(可有可无)

三、tornado.web.asynchronous 回调异步

  • 说明

    此装饰器用于回调形式的异步方法,并且应该仅用于 HTTP 的方法上(如 get、post 等)

    此装饰器不会让被装饰的方法变为异步,而只是告诉框架被装饰的方法是异步的,当方法返回时响应尚未完成。只有在 request handler 调用了 finish 方法后,才会结束本次请求处理,发送响应

    不带此装饰器的请求在 get、post 等方法返回时自动完成结束请求处理

  • 协程异步

    import tornado.web import tornado.httpclient class IndexHandler(tornado.web.RequestHandler): @tornado.gen.coroutine def get(self): http = tornado.httpclient.AsyncHTTPClient() response = yield http.fetch("http://www.baidu.com") if response.error: self.send_error(500) else: print(response.body.decode('utf-8')) f = open('baidu.html', 'wb') f.write(response.body) f.close() self.write("操作成功")

    也可以将异步 Web 请求单独出来

    import tornado.web import tornado.httpclient class IndexHandler(tornado.web.RequestHandler): @tornado.gen.coroutine def get(self): rep = yield self.get_body_info("http://www.baidu.com") if rep['ret'] == 1: print(rep['body']) self.write("成功") @tornado.gen.coroutine def get_body_info(self, url): rep = {"ret":1} http = tornado.httpclient.AsyncHTTPClient() response = yield http.fetch(url) if response.error: rep = {"ret":0} else: rep['body'] = response.body.decode('utf-8') f = open('baidu.html', 'wb') f.write(response.body) f.close() self.write("操作成功") raise tornado.gen.Return(rep) # 此处需要注意

    代码中我们需要注意的地方是 get_body_info 返回值的方式,在 python 2 中,使用了 yield 的生成器可以使用不返回任何值的 return,但不能 return value,因此 Tornado 为我们封装了用于在生成器中返回值的特殊异常 tornado.gen.Return,并用 raise 来返回此返回值

  • 并行协程

    Tornado 可以同时执行多个异步,并发的异步可以使用列表或字典

    import tornado.web import tornado.httpclient class IndexHandler(tornado.web.RequestHandler): @tornado.gen.coroutine def get(self): self.urls = ["http://www.baidu.com","http://www.webometrics.info/en/Asia"] rep1, rep2 = yield [self.get_url_info(self.urls[0]), self.get_url_info(self.urls[1])] self.write_response(self.urls[0], rep1, 'baidu.html') self.write_response(self.urls[1], rep2, 'Asia.html') def write_response(self, url, response, name): self.write(url) self.write(":<br/>") if 1 == response["ret"]: f = open(name, 'wb') f.write(response['body']) f.close() self.write("操作成功") else: self.write("获取数据失败 <br/>") @tornado.gen.coroutine def get_url_info(self, url): rep = {"ret": 1} http = tornado.httpclient.AsyncHTTPClient() response = yield http.fetch(url) if response.error: rep = {"ret": 0} else: rep['body'] = response.body raise tornado.gen.Return(rep) # 此处需要注意

四、关于数据库的异步说明

网站基本都会有数据库操作,而 Tornado 是单线程的,这意味着如果数据库查询返回过慢,整个服务器响应会被堵塞

数据库查询,实质上也是远程的网络调用;理想情况下,是将这些操作也封装成为异步的;但 Tornado 对此并 没有 提供任何支持

这是 Tornado 的 设计,而不是缺陷

一个系统,要满足高流量;是必须解决数据库查询速度问题的!

数据库若存在查询性能问题,整个系统无论如何优化,数据库都会是瓶颈,拖慢整个系统!

异步并 不能 从本质上提到系统的性能;它仅仅是避免多余的网络响应等待,以及切换线程的 CPU 耗费。

如果数据库查询响应太慢,需要解决的是数据库的性能问题;而不是调用数据库的前端 Web 应用

对于实时返回的数据查询,理想情况下需要确保所有数据都在内存中,数据库硬盘 IO 应该为 0;这样的查询才能足够快;而如果数据库查询足够快,那么前端 web 应用也就无将数据查询封装为异步的必要

就算是使用协程,异步程序对于同步程序始终还是会提高复杂性;需要衡量的是处理这些额外复杂性是否值得

如果后端有查询实在是太慢,无法绕过,Tornaod 的建议是将这些查询在后端封装独立封装成为 HTTP 接口,然后使用 Tornado 内置的异步 HTTP 客户端进行调用

正文完
星哥说事-微信公众号
post-qrcode
 
星锅
版权声明:本站原创文章,由 星锅 2022-05-26发表,共计3259字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
【腾讯云】推广者专属福利,新客户无门槛领取总价值高达2860元代金券,每种代金券限量500张,先到先得。
阿里云-最新活动爆款每日限量供应
评论(没有评论)
验证码
【腾讯云】云服务器、云数据库、COS、CDN、短信等云产品特惠热卖中