简单介绍Python的Tornado框架中的协程异步实现原理
作者:C Wong 发布时间:2021-06-21 10:00:23
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 的协程异步并不是这三言两语能说清楚的, 其中有很复杂的封装和传递, 有兴趣可以自己 阅读源码.


猜你喜欢
- 0.目录1.前言2.安装python3.使用pip下载、安装包3.1 安装Scrapy3.2 安装PyQt3.3 同时安装多个包3.4 pi
- 给图像添加颜色在使用OpenCV操作图像时,有时候需要给图像添加不同的颜色,以达到不同的风格效果。这里介绍的主要是opencv中的cv.ap
- 在我们人生的路途中,找工作是每个人都会经历的阶段,小编曾经也是苦苦求职大军中的一员。怀着对以后的规划和想象,我们在找工作的时候,会看一些招聘
- 一、数字类型。数字类型按照我的分类方法分为三类:整数类、小数类和数字类。 我所谓的“数字类”,就是指DECIMAL和NUMERIC,它们是同
- timeit.repeattimeit.repeat默认会执行3轮,每轮执行1000000次。返回每轮的总执行时间列表字典获取性能大家都知道
- 由以下函数代替该功能:def cv_imread(file_path): cv_img=cv2.imdecode(np.fromfile(f
- Reference:https://www.tensorflow.org/install/migrationtensorflow 更新到1.
- 前面我们给了Tkinter接管Python输入和输出的介绍,我们不难可以想到,能用Tkinter来开发自己的Python代码编辑器.例如可以
- HTMLParser是python用来解析html的模块。它可以分析出html里面的标签、数据等等,是一种处理html的简便途径。HTMLP
- 触发器是一种特殊类型的存储过程,它不同于之前的我们介绍的存储过程。触发器主要是通过事件进行触发被自动调用执行的。而存储过程可以通过存储过程的
- Python通过命令提示符安装matplotlib:1.直接打开命令提示符(快捷键窗口+ r)2.若提示安装失败(Python - 您正在使
- MySQLWorkbench是 MySQL AB 最近释放的可视数据库设计工具。这个工具是设计 MySQL数据库的专用工具。下载地址:htt
- 根据一般做法的话,导出部分字段时没有办法生成格式化XML文件,所以导入时就没有办法格式化导入数据。 我想到两点,1.手工修改格式化XML文件
- 前言这篇主要整理pandas常用的基本函数,主要分为五部分:汇总函数特征统计函数唯一值函数替换函数排序函数1、汇总函数常用的主要是4个:ta
- TensorFlow提供了TFRecords的格式来统一存储数据,理论上,TFRecords可以存储任何形式的数据。TFRecords文件中
- 如下所示:import osimport cv2import sysimport numpy as nppath = "F:\\I
- 本文详细讲述了DRF认证组件的原理以及用法.源码剖析讲解DRF版本的时候我们都知道了,在dispatch方法里执行了initial方法来初始
- BULK INSERT以用户指定的格式复制一个数据文件至数据库表或视图中。 语法:BULK INSERT [ [ 'database
- python读取Excel表格文件,例如获取这个文件的数据python读取Excel表格文件,需要如下步骤:1、安装Excel读取数据的库-
- 首先抛出我们在讨论使用回调编程时的一些观点:激活errback是非常重要的。由于errback的功能与except块相同,因此用户需要确保它