学习tornado:异步
why asynchronous
tornado是一个异步web framework,说是异步,是因为tornado server与client的网络交互是异步的,底层基于io event loop。但是如果client请求server处理的handler里面有一个阻塞的耗时操作,那么整体的server性能就会下降。
def MainHandler(tornado.web.RequestHandler):
def get(self):
client = tornado.httpclient.HttpClient()
response = client.fetch("http://www.google.com/")
self.write('Hello World')
在上面的例子中,tornado server的整体性能依赖于访问google的时间,如果访问google的时间比较长,就会导致整体server的阻塞。所以,为了提升整体的server性能,我们需要一套机制,使得handler处理都能够通过异步的方式实现。
幸运的是,tornado提供了一套异步机制,方便我们实现自己的异步操作。当handler处理需要进行其余的网络操作的时候,tornado提供了一个async http client用来支持异步。
def MainHandler(tornado.web.RequestHandler):
@tornado.web.asynchronous
def get(self):
client = tornado.httpclient.AsyncHTTPClient()
def callback(response):
self.write("Hello World")
self.finish()
client.fetch("http://www.google.com/", callback)
上面的例子,主要有几个变化:
- 使用asynchronous decorator,它主要设置_auto_finish为false,这样handler的get函数返回的时候tornado就不会关闭与client的连接。
- 使用AsyncHttpClient,fetch的时候提供callback函数,这样当fetch http请求完成的时候才会去调用callback,而不会阻塞。
- callback调用完成之后通过finish结束与client的连接。
asynchronous flaw
异步操作是一个很强大的操作,但是它也有一些缺陷。最主要的问题就是在于callback导致了代码逻辑的拆分。对于程序员来说,同步顺序的想法是一个很自然的习惯,但是异步打破了这种顺序性,导致代码编写的困难。这点,对于写nodejs的童鞋来说,可能深有体会,如果所有的操作都是异步,那么最终我们的代码可能写成这样:
def MainHandler(tornado.web.RequestHandler):
@tornado.web.asynchronous
def get(self):
client = tornado.httpclient.AsyncHTTPClient()
def callback1(response):
def callback2(response):
self.write("Hello World")
self.finish()
client.fetch("http://www.google.com", callback2)
client.fetch("http://www.google.com/", callback1)
也就是说,我们可能会写出callback嵌套callback的情况,这个极大的会影响代码的阅读与流程的实现。
synchronous
我个人认为,异步拆散了代码流程这个问题不大,毕竟如果一个逻辑需要过多的嵌套callback来实现的话,那么我们就需要考虑这个逻辑是否合理了,所以异步一般也不会有过多的嵌套层次。
虽然我认为异步的callback问题不大,但是如果仍然能够有一套机制,使得异步能够顺序化,那么对于代码逻辑的编写来说,会方便很多。tornado有一些机制来实现。
yield
在python里面如果一个函数内部实现了yield,那么这个函数就不是函数了,而是一个生成器,它的整个运行机制也跟普通函数不一样,举一个例子:
def test_yield():
print 'yield 1'
a = yield 'yielded'
print 'over', a
t = test_yield()
print 'main', type(t)
ret = t.send(None)
print ret
try:
t.send('hello yield')
except StopIteration:
print 'yield over'
输出结果如下:
main <type 'generator'>
yield 1
yielded
over hello yield
yield over
从上面可以看到,test_yield是一个生成器,当它第一次调用的时候,只是生成了一个Generator,不会执行。当第一次调用send的时候,生成器被resume,开始执行,然后碰到yield,就挂起,等待下一次被send唤醒。当生成器执行完毕,会抛出StopIteration异常,供外部send的地方知晓。
因为yield很方便的提供了一套函数挂起,运行的机制,所以我们能够通过yield来将原本是异步的流程变成同步的。
gen
tornado有一个gen模块,提供了Task和Callback/Wait机制用来支持同步模型,以task为例:
def MainHandler(tornado.web.RequestHandler):
@tornado.web.asynchronous
@tornado.gen.engine
def get(self):
client = tornado.httpclient.AsyncHTTPClient()
response = yield tornado.gen.Task(client.fetch, "http://www.google.com/")
self.write("Hello World")
self.finish()
可以看到,tornado的gen模块就是通过yield来进行同步化的。主要有如下需要注意的地方:
- 使用gen.engine的decorator,该函数主要就是用来管理generator的流程控制。
- 使用了gen.Task,在gen.Task内部,会生成一个callback函数,传给async fetch,并执行fetch,因为fetch是一个异步操作,所以会很快返回。
- 在gen.Task返回之后使用yield,挂起
- 当fetch的callback执行之后,唤醒挂起的流程继续执行。
可以看到,使用gen和yield之后,原先的异步逻辑变成了同步流程,在代码的阅读性上面就有不错的提升,不过对于不熟悉yield的童鞋来说,开始反而会很迷惑,不过只要理解了yield,那就很容易了。
greenlet
虽然yield很强大,但是它只能挂起当前函数,而无法挂起整个堆栈,这个怎么说呢,譬如我想实现下面的功能:
def a():
yield 1
def b():
a()
t = b()
t.send(None)
这个通过yield是无法实现的,也就是说,a里面使用yield,它是一个生成器,但是a的挂起无法将b也同时挂起。也就是说,我们需要一套机制,使得堆栈在任何地方都能够被挂起和恢复,能方便的进行栈切换,而这套机制就是coroutine。
最开始使用coroutine是在lua里面,它原生提供了coroutine的支持。然后在使用luajit的时候,发现内部是基于fiber(win)和context(unix),也就是说,不光lua,其实c/c++我们也能实现coroutine。现在研究了go,也是内置coroutine,并且这里极力推荐一篇slide。
python没有原生提供coroutine,不知道以后会不会有。但有一个greenlet,能帮我们实现coroutine机制。而且还有人专门写好了tornado与greenlet结合的模块,叫做greenlet_tornado,使用也很简单
class MainHandler(tornado.web.RequestHandler):
@greenlet_asynchronous
def get(self):
response = greenlet_fetch('http://www.google.com')
self.write("Hello World")
self.finish()
可以看到,使用greenlet,能更方便的实现代码逻辑,这点比使用gen更方便,因为这些连写代码的童鞋都不用去纠结yield问题了。
总结
这里只是简单的介绍了tornado的一些异步处理流程,以及将异步同步化的一些方法。另外,这里举得例子都是网络http请求方面的,但是server处理请求的时候,可能还需要进行数据库,本地文件的操作,而这些也是同步阻塞耗时操作,同样可以通过异步来解决的,这里就不详细说明了。
学习tornado:异步的更多相关文章
- 5.(基础)tornado异步
终于到了传说中的异步了,感觉异步这个名字听起来就很酷酷的,以前还不是多擅长Python时,就跑去看twisted的源码,结果给我幼小的心灵留下了创伤.反正包括我在内,都知道异步编程很强大,但是却很少在 ...
- 7.2 Tornado异步
7.2 Tornado异步 因为epoll主要是用来解决网络IO的并发问题,所以Tornado的异步编程也主要体现在网络IO的异步上,即异步Web请求. 1. tornado.httpclient.A ...
- tornado异步请求的理解(转)
tornado异步请求的理解 http://www.kankanews.com/ICkengine/archives/88953.shtml 官网第一段话: Tornado is a Python w ...
- 使用Tornado异步接入第三方(支付宝)支付
目前国内比较流行的第三方支付主要有支付宝和微信支付,博主最近研究了下如何用Python接入支付宝支付,这里我以Tornado作为web框架,接入支付宝构造支付接口. 使用Tornado异步接入支付宝支 ...
- Tornado异步非阻塞的使用以及原理
Tornado 和现在的主流 Web 服务器框架(包括大多数 Python 的框架)有着明显的区别:它是非阻塞式服务器,而且速度相当快.得利于其 非阻塞的方式和对 epoll 的运用,Tornado ...
- Python Web框架 tornado 异步原理
Python Web框架 tornado 异步原理 参考:http://www.jb51.net/article/64747.htm 待整理
- [译]聊聊C#中的泛型的使用(新手勿入) Seaching TreeVIew WPF 可编辑树Ztree的使用(包括对后台数据库的增删改查) 字段和属性的区别 C# 遍历Dictionary并修改其中的Value 学习笔记——异步 程序员常说的「哈希表」是个什么鬼?
[译]聊聊C#中的泛型的使用(新手勿入) 写在前面 今天忙里偷闲在浏览外文的时候看到一篇讲C#中泛型的使用的文章,因此加上本人的理解以及四级没过的英语水平斗胆给大伙进行了翻译,当然在翻译的过程中发 ...
- Tornado异步(2)
Tornado异步 因为epoll主要是用来解决网络IO的并发问题,所以Tornado的异步编程也主要体现在网络IO的异步上,即异步Web请求. 1. tornado.httpclient.Async ...
- tornado异步(1)
1. 同步 我们用两个函数来模拟两个客户端请求,并依次进行处理: # coding:utf-8 def req_a(): """模拟请求a""&quo ...
- 第一次学习tornado小练习
内容 这次是python的一个web框架,tornado,这个web框架在python的几个web框架中一个比较简单的web框架,刚开始接触python的时候就知道python有两个比较常用的web框 ...
随机推荐
- Python小代码_14_交换 2 个变量的 3 种方式
a = 4 b = 5 #第一种 c = a a = b b = c print(a, b) #输出结果 #5 4 #第二种 a = a + b b = a - b a = a - b print(a ...
- vim基本操作
Vim 是 Linux 系统上的最著名的文本/代码编辑器,也是早年的 Vi 编辑器的加强版,而 gVim 则是其 Windows 版.它的最大特色是完全使用键盘命令进行编辑,脱离了鼠标操作虽然使得入门 ...
- 0. 迷之 -> 和 .
0. 迷之 -> 和 . 箭头(->):左边必须为指针: 点号(.):左边必须为实体. e.g.1 class class A{ public: play(); }; int main() ...
- nginx的yum安装,基本参数使用,编译参数说明和Nginx基本配置,模块安装
nginx的yum安装从nginx官网获取源 vim /etc/yum.repose.d/nginx.repo[nginx]name=nginx repobaseurl=http://nginx.or ...
- python socket网络编程之粘包问题详解
一,粘包问题详情 1,只有TCP有粘包现象,UDP永远不会粘包 你的程序实际上无权直接操作网卡的,你操作网卡都是通过操作系统给用户程序暴露出来的接口,那每次你的程序要给远程发数据时,其实是先把数据从用 ...
- Spring-cloud(六) Hystrix入门
前提 一个可用的Eureka注册中心(文中以之前博客中双节点注册中心,不重要) 一个连接到这个注册中心的服务提供者 快速入门 项目搭建 搭建一个新maven项目,artifactid为Ribbon-c ...
- html学习中
Html常用标签一 <body style="background-color:red;"> Body 标签 Style 属性 background-color:red ...
- Bootstrap3 表格-状态类
通过这些状态类可以为行或单元格设置颜色. .active---鼠标悬停在行或单元格上时所设置的颜色 .success--–标识成功或积极的动作 .info----标识普通的提示信息或动作 .warni ...
- 在linux系统中I/O 调度的选择
I/O 调度算法再各个进程竞争磁盘I/O的时候担当了裁判的角色.他要求请求的次序和时机做最优化的处理,以求得尽可能最好的整体I/O性能. 在linux下面列出4种调度算法 CFQ (Compl ...
- Dynamics 365 你所期待的子网格编辑终于来了
Dynamics 365的online版本已经在11月1号发布了,on-premises版也在没几天后发布,今天略看了一眼 what's new 一眼就看到了 editable grids,这个不用我 ...