简单介绍Python的Tornado框架中的协程异步实现原理


Posted in Python onApril 23, 2015

Tornado 4.0 已经发布了很长一段时间了, 新版本广泛的应用了协程(Future)特性. 我们目前已经将 Tornado 升级到最新版本, 而且也大量的使用协程特性.

很长时间没有更新博客, 今天就简单介绍下 Tornado 协程实现原理, Tornado 的协程是基于 Python 的生成器实现的, 所以首先来回顾下生成器.
生成器

Python 的生成器可以保存执行状态 并在下次调用的时候恢复, 通过在函数体内使用 yield 关键字 来创建一个生成器, 通过内置函数 next 或生成器的 next 方法来恢复生成器的状态.

def test():
  yield 1

我们调用 test 函数, 此时并不会返回结果, 而是会返回一个生成器

>>> test()
<generator object test at 0x100b3b320>

我们调用其 next 方法则返回 yield 关键字之后的内容.

>>> t = test()
>>> t.next()
1

如果我们接着调用 next 方法, 后面又没有 yield 关键字继续返回的话, 会抛出一个 StopIteration 异常.

yield 关键字不仅仅能从生成器内部返回状态, 同时也可以将外部信息传递到生成器内部, 通过将 yeild 关键里赋值给变量, 并调用生成器的 send 方法来将对象传递到生成器 内部. 需要注意的是生成器的开始必须调用其 next 方法, 后面 send 方法调用的同时 也会触发 next 动作. 如果没有变量接收 yield 关键字那么 send 传递的值将会 被丢弃.

>>> def test():
  a = yield
  print(a)

首先调用 next 上面函数返回的生成器将返回 None, 如果这时候直接调用 next 将 会给生成器发送 None, 如果调用 send 发送一个值, 将打印这个值并抛出 StopIteration 异常.
一个简单地协程

以上就是实现协程的所有基础, 为了加深理解, 我们这里写一个小例子, 例子我们只使用协程 开启两个甚至多个死循环, 下面就是一个极其简单地例子::

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from __future__ import absolute_import, print_function, division, with_statement

def loop1():
  """ 循环1负责抛出一个函数和对应的参数, 并接收结果
  """
  a = 0
  ret = 1
  while True:
    ret = yield sum, [a, ret]
    a, ret = ret, a
    print("Loop1 ret", ret)
def loop2():
  """ 循环2 负责接收函数并计算结果, 然后 yield 出结果
  """
  while True:
    func, args = yield
    yield func(args)
    print("Loop2")


l1 = loop1()
l2 = loop2()
tmp = l1.next()

for i in range(10):
  l2.next()
  ret = l2.send(tmp)
  tmp = l1.send(ret)

上面例子里 loop1 负责产生任务, loop2 负责执行任务, 主循环负责调度任务并将任务结果发回给 任务产生者.
Tornado 如何做的

我们首先看一个使用 Tornado 协程异步的例子

#!/usr/bin/env python
# -*- coding:utf-8 -*-

from __future__ import absolute_import, print_function, division, with_statement

from tornado import gen
from tornado import web
from tornado import httpclient


class ActionHandler(web.RequestHandler):

  @gen.coroutine
  def get(self):
    response = yield httpclient.AsyncHTTPClient().fetch("http://www.linuxzen.com")

    # ...

其实原理在上面简单地例子里已经讲清楚了, 我们来简单分析一遍上面的例子, 首先 Tornado 得到 ActionHandler.get 方法抛出(next)的一个任务, 然后异步的去执行任务, 当任务(网络请求)结束或 异常时 Tornado 取得事件通知然后将结果放回(send)到该方法中让该方法继续执行.

由于是异步的, 调用这个方法并不会阻塞其他任务执行.

这时候我们的方法其实就是上个例子 loop1 函数, 而 Tornado 调度并执行了其抛出的任务.
总结

Tornado 的协程异步可以让异步看起来是顺序执行的, 可以从一大串的 callback 中解脱出来.

Tornado 的协程异步并不是这三言两语能说清楚的, 其中有很复杂的封装和传递, 有兴趣可以自己 阅读源码.

Python 相关文章推荐
Python图片裁剪实例代码(如头像裁剪)
Jun 21 Python
11月编程语言排行榜 Python逆袭C#上升到第4
Nov 15 Python
python读取和保存视频文件
Apr 16 Python
使用memory_profiler监测python代码运行时内存消耗方法
Dec 03 Python
浅谈python str.format与制表符\t关于中文对齐的细节问题
Jan 14 Python
python 实现返回一个列表中出现次数最多的元素方法
Jun 11 Python
python 修改本地网络配置的方法
Aug 14 Python
PYTHON如何读取和写入EXCEL里面的数据
Oct 28 Python
用Python画小女孩放风筝的示例
Nov 23 Python
浅谈Python的方法解析顺序(MRO)
Mar 05 Python
Python2及Python3如何实现兼容切换
Sep 01 Python
PyTorch 中的傅里叶卷积实现示例
Dec 11 Python
解决Python中由于logging模块误用导致的内存泄露
Apr 23 #Python
粗略分析Python中的内存泄漏
Apr 23 #Python
使用beaker让Facebook的Bottle框架支持session功能
Apr 23 #Python
用Python编写脚本使IE实现代理上网的教程
Apr 23 #Python
在Python的Bottle框架中使用微信API的示例
Apr 23 #Python
最基础的Python的socket编程入门教程
Apr 23 #Python
利用Python实现简单的相似图片搜索的教程
Apr 23 #Python
You might like
真正根据utf8编码的规律来进行截取字符串的函数(utf8版sub_str )
2012/10/24 PHP
深入理解ob_flush和flush的区别(ob_flush()与flush()使用方法)
2013/02/06 PHP
php的declare控制符和ticks教程(附示例)
2014/03/21 PHP
php使用array_rand()函数从数组中随机选择一个或多个元素
2014/04/28 PHP
Joomla调用系统自带编辑器的实现方法
2016/05/05 PHP
PHP实现简单登录界面
2019/10/23 PHP
ExtJS 工具栏 分页事件参数
2010/03/05 Javascript
BootStrap Table 分页后重新搜索问题的解决办法
2016/08/08 Javascript
更靠谱的H5横竖屏检测方法(js代码)
2016/09/13 Javascript
vue中用动态组件实现选项卡切换效果
2017/03/25 Javascript
简单实现jquery隔行变色
2017/11/09 jQuery
浅谈jquery fullpage 插件增加头部和版权的方法
2018/03/20 jQuery
JavaScript事件委托原理与用法实例分析
2018/06/07 Javascript
详解JSON Web Token 入门教程
2018/07/30 Javascript
详细讲解如何创建, 发布自己的 Vue UI 组件库
2019/05/29 Javascript
使用 Vue 实现一个虚拟列表的方法
2019/08/20 Javascript
使用layui实现树形结构的方法
2019/09/20 Javascript
matplotlib绘制动画代码示例
2018/01/02 Python
PyQt5实现QLineEdit添加clicked信号的方法
2019/06/25 Python
Python中的X[:,0]、X[:,1]、X[:,:,0]、X[:,:,1]、X[:,m:n]和X[:,:,m:n]
2020/02/13 Python
python实现图像随机裁剪的示例代码
2020/12/10 Python
python字典按照value排序方法
2020/12/28 Python
详解Canvas实用库Fabric.js使用手册
2019/01/07 HTML / CSS
联想香港官方网站及网店:Lenovo香港
2018/04/13 全球购物
经典的班主任推荐信
2013/10/28 职场文书
毕业生自我鉴定实例
2014/01/21 职场文书
党员组织关系介绍信
2014/02/13 职场文书
班级文化建设标语
2014/06/23 职场文书
档案工作汇报材料
2014/08/21 职场文书
库房管理员岗位职责
2015/02/12 职场文书
北京青年观后感
2015/06/15 职场文书
2015入党自传格式范文
2015/06/26 职场文书
《折线统计图》教学反思
2016/02/22 职场文书
雄兵连:第三季先行图公开,天使恶魔联合,银河之力的新力量
2021/06/11 国漫
Python使用psutil库对系统数据进行采集监控的方法
2021/08/23 Python
spring cloud 配置中心native配置方式
2021/09/25 Java/Android