Tornado 协程
同步异步I/O客户端
from tornado.httpclient import HTTPClient,AsyncHTTPClient def ssync_visit():
http_client = HTTPClient()
response = http_client.fetch('www.baidu.com') # 阻塞,直到网站请求完成
print(response.body) def hendle_response(response):
print(response.body)
def async_visit():
http_client = AsyncHTTPClient()
http_client.fetch('www.baidu.com',callback=hendle_response) # 非阻塞 async_visit()
协程
1、编写协程函数
from tornado import gen # 引入协程库 from tornado.httpclient import AsyncHTTPClient @gen.coroutine
def coroutine_visit():
http_client = AsyncHTTPClient()
response = yield http_client.fetch('www.baidu.com')
print(response.body)
2、调用协程函数
由于Tornado协程基于python的yield关键字实现,所以不能调用普通函数一样调用协程函数
协程函数可通过以下三种方式调用
- 在本身是协程的函数内通过yield关键字调用
- 在IOLoop尚未启动时,通过IOLoop的run_sync()函数调用
- 在IOLoop已经启动时,通过IOLoop的spawn_callback()函数调用
下面是一个通过协程函数调用协程函数的例子
@gen.coroutine
def outer_coroutine():
print('开始调用另一个协程')
yield coroutine_visit()
print('outer_coroutine 调用结束')
outer_coroutine和coroutine_visit都是协程函数,他们之间可以通过yield关键字进行调用 IOLoop 是Tornado的主事件循环对象,Tornado程序通过它监听外部客户端的访问请求,并执行相应的操作,当程序尚未进入IOLoop的runing状态时,可以通过run_sync()函数调用协程函数,比如:
from tornado import gen # 引入协程库
from tornado.ioloop import IOLoop
from tornado.httpclient import AsyncHTTPClient @gen.coroutine
def coroutine_visit():
http_client = AsyncHTTPClient()
response = yield http_client.fetch('http://www.baidu.com')
print(response.body) def func_normal():
print('开始调用协程')
IOLoop.current().run_sync(lambda: coroutine_visit())
print('结束协程调用')
func_normal()
本例中run_sync()函数将当前函数的执行进行阻塞,直到被调用的协程执行完成
Tornado 要求协程函数在IOloop的running状态才能被调用,只不过run_sync函数自动完成了启动,停止IOLoop的步骤,他的实现逻辑为:启动IOLoop-调用被lambda封装的协程函数-停止IOLoop
当tornado程序已经处于running 状态时协程的调用如下:
def func_normal():
print('开始调用协程')
IOLoop.current().spawn_callback(coroutine_visit)
print('结束协程调用')
func_normal()
开始调用协程
结束协程调用
本例中spawn_callback函数不会等待被调用的协程执行完成,而协程函数将会由IOLoop在合适的时机进行调用,并且spawn_callback函数没有提供电泳返回值的方法,所以hi能用该函数调用没有返回值的协程函数
3、在协程中调用阻塞函数
在协程中直接调用阻塞函数会影响协程本身的性能,所以tornado提供了在协程中利用线程池调度阻塞函数,从而不影响协程本身继续执行的方法,实例代码如下:
from concurrent.futures import ThreadPoolExecutor
from tornado import gen
thread_pool = ThreadPoolExecutor(2) def mySleep(count):
import time
for i in range(count):
time.sleep(1) @gen.coroutine
def call_backing():
print('开始调用当前函数')
yield thread_pool.submit(mySleep,10)
print('结束调用') call_backing()
4、在协程中的等待多个异步调用
tornado允许在协程中用一个yield关键字等待多个异步调用,只需把这些调用用列表或字典的方式传递给yield关键字即可
实例如下:
from tornado import gen # 引入协程库
from tornado.ioloop import IOLoop
from tornado.httpclient import AsyncHTTPClient @gen.coroutine
def coroutine_visit():
http_client = AsyncHTTPClient()
list_response = yield [http_client.fetch('http://www.baidu.com'),
http_client.fetch('http://www.sina.com'),
http_client.fetch('http://www.163.com')
]
for response in list_response:
print(response.body) def func_normal():
print('开始调用协程')
IOLoop.current().run_sync(lambda: coroutine_visit())
print('结束协程调用')
func_normal()
字典同理,不再演示
Tornado 网站
异步化,协程化
当大量客户端高并发请求场景出现时,需要用到两种方式改变同步的处理请求流程
- 异步化:针对RequestHandler的处理函数使用@tornado.web.asynchronous修饰器,将默认同步机制改成异步机制
- 协程化:针对RequestHandler的处理函数使用@tornado.gen.coroutine修饰器,将默认的同步机制还成协程机制
1、异步化
from tornado import web,httpclient
import tornado
class MainHandler(tornado.web.RequestHandler): @tornado.web.asynchronous
def get(self):
http = tornado.httpclient.AsyncHTTPClient()
http.fetch('http://www.baidu.com',callback=self.on_response)
def on_response(self,response):
if response.error:
raise tornado.web.HTTPError(500)
self.write(response.body)
self.finish()
用@tornado.web.asynchronous 定义HTTP访问处理函数get(),当get函数返回时对该访问的请求尚未完成,所以tornado无法发送响应给客户端,只有随后的回掉函数中的finsh函数被调用时,tornado才知道本次处理已经完成,可以发送响应给客户端
异步虽然提高了并发能力,但是编程方法更繁琐
2、协程化
tornado 协程结合同步异步的优点,
import tornado.web
import tornado.httpclient
class MainHandler(tornado.web.RequestHandler): @tornado.gen.coroutine
def get(self):
http = tornado.httpclient.AsyncHTTPClient()
response = yield http.fetch('http://www.baidu.com')
self.write(response.body)
用tornado.gen.coroutine装饰MainHandler的get(),post()函数
使用异步对象处理耗时操作,比如AsyncHTTPClient
调用yield关键字获取异步对象的处理结果
实践中的异步
下各项同步(阻塞)的,如果在 tornado 中按照之前的方式只用它们,就是把 tornado 的非阻塞、异步优势削减了。
- 数据库的所有操作,不管你的数据是 SQL 还是 noSQL,connect、insert、update 等
- 文件操作,打开,读取,写入等
- time.sleep
- smtplib,发邮件的操作
- 一些网络操作,比如 tornado 的 httpclient 以及 pycurl 等
解决方法
- 在数据库方面,由于种类繁多,不能一一说明,比如 mysql,可以使用adb模块来实现 python 的异步 mysql 库;对于 mongodb 数据库,有一个非常优秀的模块,专门用于在 tornado 和 mongodb 上实现异步操作,它就是 motor。
- 文件操作方面也没有替代模块,只能尽量控制好 IO,或者使用内存型(Redis)及文档型(MongoDB)数据库。
- time.sleep() 在 tornado 中有替代:yield
tornado.gen.sleep()或者tornado.ioloop.IOLoop.instance().add_timeout - smtp 发送邮件,推荐改为 tornado-smtp-client。
- 对于网络操作,要使用 tornado.httpclient.AsyncHTTPClient。
greenlet-tornado 可以实现用专门的库来实现tornado 的异步而不使用装饰器的异步
Tornado 协程的更多相关文章
- tornado用户指引(三)------tornado协程使用和原理(二)
Python3.5 async和await async和await是python3.5引入的2个新的关键字(用这两个关键字编写的函数也称之为"原生协程"). 从tornado4. ...
- tornado用户指引(二)------------tornado协程实现原理和使用(一)
摘要:Tornado建议使用协程来实现异步调用.协程使用python的yield关键字来继续或者暂停执行,而不用编写大量的callback函数来实现.(在linux基于epoll的异步调用中,我们需要 ...
- tornado 协程的实现原理个人理解;
tornado实现协程的原理主要是利用了(1)python里面的generator (2)future类和ioloop相互配合,两者之间的相互配合是通过gen.coroutine装饰器来实现的: 具体 ...
- tornado用户指引(四)------tornado协程使用和原理(三)
版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/happyAnger6/article/details/51291221几种常用的协程方式: 1.回调 ...
- Python协程 Gevent Eventlet Greenlet
https://zh.wikipedia.org/zh-cn/%E5%8D%8F%E7%A8%8B 协程可以理解为线程中的微线程,通过手动挂起函数的执行状态,在合适的时机再次激活继续运行,而不需要上下 ...
- 分析Tornado的协程实现
转自:http://www.binss.me/blog/analyse-the-implement-of-coroutine-in-tornado/ 什么是协程 以下是Wiki的定义: Corouti ...
- 深入tornado中的协程
tornado使用了单进程(当然也可以多进程) + 协程 + I/O多路复用的机制,解决了C10K中因为过多的线程(进程)的上下文切换 而导致的cpu资源的浪费. tornado中的I/O多路复用前面 ...
- python tornado TCPserver异步协程实例
项目所用知识点 tornado socket tcpserver 协程 异步 tornado tcpserver源码抛析 在tornado的tcpserver文件中,实现了TCPServer这个类,他 ...
- Python开发【模块】:tornado.queues协程的队列
协程的队列 协调生产者消费者协程. from tornado import gen from tornado.ioloop import IOLoop from tornado.queues impo ...
随机推荐
- 求字符串空格、数字、字母个数--JAVA基础
相关内容:charAt()函数 package com.nxl123.www;public class NumString { public static void main(String[] arg ...
- 【BZOJ2959】长跑(Link-Cut Tree,并查集)
[BZOJ2959]长跑(Link-Cut Tree,并查集) 题面 BZOJ 题解 如果保证不出现环的话 妥妥的\(LCT\)傻逼题 现在可能会出现环 环有什么影响? 那就可以沿着环把所有点全部走一 ...
- (1)Deep Learning之感知器
What is deep learning? 在人工智能领域,有一个方法叫机器学习.在机器学习这个方法里,有一类算法叫神经网络.神经网络如下图所示: 上图中每个圆圈都是一个神经元,每条线表示神经元之间 ...
- Bounding-box 回归
R-CNN系列均训练了Bounding-box回归器来对窗口进行校正,其目标是学习一种转换关系将预测得到的窗口P映射为真实窗口G(Ground truth). 变换方式 可以通过简单的仿射变换以及指数 ...
- checkBox半选中状态
checkbox 可以半选中,这个特性,很多浏览器都支持 // 用 input.indeterminate 这个属性来获取或者设置半选中状态,必须要用 js 添加属性,才有效果. input.inde ...
- 简简单单把event loop说清楚
event loop这东西,确实把我坑了一把,面试的时候被问到这个问题的时候,我是懵逼的,完全不知道怎么回答,而当我回来查到原来这个听起来如此玄乎又厉害的名字就是异步和单线程那块的知识的时候,我心情又 ...
- redis笔记总结之redis介绍
一.Redis介绍: redis的发展历史简单的理解为因为使用类似MySql这类关系型数据库不方便进而开发的开源的.轻量级的.非关系型的,直到现在一直不断完善的一款NoSql数据库.具体的介绍大家可以 ...
- P2P技术简介
P2P技术简介 NAT( Network Address Translation)穿越(俗称打洞)技术 前言: p2p已经存在于我们生活的方方面面:我们通过下载在工具(比如迅雷,bitorent,各种 ...
- Lucene就是这么简单
什么是Lucene?? Lucene是apache软件基金会发布的一个开放源代码的全文检索引擎工具包,由资深全文检索专家Doug Cutting所撰写,它是一个全文检索引擎的架构,提供了完整的创建索引 ...
- 炫丽的倒计时效果Canvas绘图与动画基础
前言 想要在自己做的网页中,加入canvas动画效果,但是发现模板各种调整不好,觉得还是要对canvas有所了解,才可以让自己的网页变得狂拽炫酷吊炸天! 一.绘制基础 1 <!DOCTYPE h ...