tornado用户指引(二)------------tornado协程实现原理和使用(一)
摘要:Tornado建议使用协程来实现异步调用。协程使用python的yield关键字来继续或者暂停执行,而不用编写大量的callback函数来实现。(在linux基于epoll的异步调用中,我们需要自己显式的为异步执行结果安装大量的callback函数).协程的使用和编写异步代码一样简单,而且省去了线程的开销。协程使编写并发程序更加容易,而且没有上下文切换的开销。举例:
from tornado import gen
@gen.coroutine
def fetch_coroutine(url)
Tornado建议使用协程来实现异步调用。
协程使用python的yield关键字来继续或者暂停执行,而不用编写大量的callback函数来实现。(在linux基于epoll的异步调用中,我们需要自己显式的为异步执行结果安装大量的callback函数).
协程的使用和编写异步代码一样简单,而且省去了线程的开销。
协程使编写并发程序更加容易,而且没有上下文切换的开销。
举例:
from tornado import gen
@gen.coroutine
def fetch_coroutine(url):
http_client = AsyncHTTPClient()
response = yield http_client.fetch(url)
# 在python3.3以前的版本中, 在一个生成器函数中返回值是不允许的。你需要通过抛出异常的方式来达到相同的目的。
return response.body
@gen.coroutine是tornado实现的一个生成器,用来将fetch_coroutine函数包装为一个协程,可以把这个协程当作一个和线程等价的执行体。这个执行体会被tornado总的ioloop调用,并在需要阻塞时切换到其它协程执行,当阻塞调用完成时,ioloop会继续执行这个就绪的协程。通过这样的方式,可以在一个线程中执行多个协程,而且不会因为某个协程阻塞而阻塞其它就绪的协程。
实现原理:
包装后的函数会返回一个Future,当这个协程真正执行完成后,会设置Future的执行结果。可以通过yield来等待这个协程执行完成并得到结果。
当协程执行yield http_client.fetch时,由于这个操作是一个网络I/O操作,属于阻塞操作。因此这个协程会暂停执行,进而tornado总的ioloop可以执行其它协程。
在协程里面,yield语句阻塞的函数需要返回一个Future,这个Future代表了一个异步执行体,并在异步操作执行完成时设置Future的结果,tornado会在Future执行完成时,将Future的执行结果通过生成器的send方法将值传回yield语句,进而唤醒阻塞的协程继续运行。
在实现上,http_client.fetch操作会通过将fd加入tornado ioloop的方式实现真正的异步操作,当fetch真正成功时,即epoll返回时,会设置Future的结果,并将此协程唤醒继续执行。
综上所述,我们要利用tornado的协程功能,需要用@gen.coroutine包装我们的函数,并在需要阻塞的地方用yield语句阻塞。阻塞的代码需要返回一个Future,并通过某种异步方式将Future的执行结果设置好。
使用tornado协程举例:
1.我们可以在协程不执行任何阻塞操作,这样协程会一直执行直到完成:
我们创建2个协程和一个总的协程,由于协程里没有阻塞操作,所以实际上两个协程是顺序执行完成的。
from tornado import gen
from tornado.ioloop import IOLoop
@gen.coroutine
def cor(n,str):
for i in range(n):
print(str,i)
return
@gen.coroutine
def main():
cor(3,"first")
cor(4,"second")
IOLoop.instance().run_sync(main)
2.有阻塞操作的协程: 我们在协程循环中增加了睡眠操作,这个sleep是tornado框架实现的,注意上面分析的过程,这个yield需要返回一个future. 另外,在main中我们也增加了yield操作,是因为要等待2个协程执行完再结束ioloop.否则程序会直接结束。 这样,可以看到2个协程交替执行,sleep操作并不会阻塞另外一个协程。
from tornado import gen
from tornado.ioloop import IOLoop
@gen.coroutine
def cor(n,str):
for i in range(n):
print(str,n)
yield gen.sleep(1)
return
@gen.coroutine
def main():
cor(3,"first")
cor(3,"second")
yield gen.sleep(3)
IOLoop.instance().run_sync(main)
3.如果把2中main函数代码改成下面这样,这样main协程就会等待第一个协程执行完,才会执行第2个协程。
@gen.coroutine
def main():
yield cor(3,"first")
yield cor(3,"second")
IOLoop.instance().run_sync(main)
tornado用户指引(二)------------tornado协程实现原理和使用(一)的更多相关文章
- 二、深入asyncio协程(任务对象,协程调用原理,协程并发)
由于才开始写博客,之前都是写笔记自己看,所以可能会存在表述不清,过于啰嗦等各种各样的问题,有什么疑问或者批评欢迎在评论区留言. 如果你初次接触协程,请先阅读上一篇文章初识asyncio协程对asy ...
- 图解Go协程调度原理,小白都能理解
阅读本文仅需五分钟,golang协程调度原理,小白也能看懂,超实用. 什么是协程 对于进程.线程,都是有内核进行调度,有CPU时间片的概念,进行抢占式调度.协程,又称微线程,纤程.英文名Corouti ...
- Unity 协程(Coroutine)原理与用法详解
前言: 协程在Unity中是一个很重要的概念,我们知道,在使用Unity进行游戏开发时,一般(注意是一般)不考虑多线程,那么如何处理一些在主任务之外的需求呢,Unity给我们提供了协程这种方式 为啥在 ...
- tornado用户指引(三)------tornado协程使用和原理(二)
Python3.5 async和await async和await是python3.5引入的2个新的关键字(用这两个关键字编写的函数也称之为"原生协程"). 从tornado4. ...
- tornado用户指引(四)------tornado协程使用和原理(三)
版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/happyAnger6/article/details/51291221几种常用的协程方式: 1.回调 ...
- Py修行路 python基础 (十二) 协程函数应用 列表生成式 生成器表达式
一.知识点整理: 1.可迭代的:对象下有_iter_方法的都是可迭代的对象 迭代器:对象._iter_()得到的结果就是迭代器 迭代器的特性: 迭代器._next_() 取下一个值 优点: 1.提供了 ...
- python进阶(二) 多进程+协程
我们大多数的时候使用多线程,以及多进程,但是python中由于GIL全局解释器锁的原因,python的多线程并没有真的实现 实际上,python在执行多线程的时候,是通过GIL锁,进行上下文切换线程执 ...
- python 并发专题(十三):asyncio (二) 协程中的多任务
. 本文目录# 协程中的并发 协程中的嵌套 协程中的状态 gather与wait . 协程中的并发# 协程的并发,和线程一样.举个例子来说,就好像 一个人同时吃三个馒头,咬了第一个馒头一口,就得等这口 ...
- 写个百万级别full-stack小型协程库——原理介绍
其实说什么百万千万级别都是虚的,下面给出实现原理和测试结果,原理很简单,我就不上图了: 原理:为了简单明了,只支持单线程,每个协程共享一个4K的空间(你可以用堆,用匿名内存映射或者直接开个数组也都是可 ...
随机推荐
- Oracle基础之count(1)和count(*)的区别
在数据库中Count(*)或者Count(1)或者Count([列])或许是最常用的聚合函数.很多人其实对这三者之间是区分不清的.本文会阐述这三者的作用,关系以及背后的原理. 我在网上看到一些所谓的优 ...
- metasploit 连接database相关问题
我们首先去这个目录下看database.yml文件内容: 下图是我们看到的的信息 接着打开metasploit,运行db_connect 指令链接数据库.格式为: db_connect 用户名:密码@ ...
- SVN学习---使用 Visual SVN 搭建SVN服务器
1.1. 使用 Visual SVN 搭建SVN服务器 搭建纯粹SVN服务器 --- svn:// 访问资源 将SVN 和 Apache服务器整合 ,搭建web SVN服务器 ---- https: ...
- 正则表达式 (python)
正则表达式 在正则表达式中,如果直接给出字符,就是精确匹配. 用\d可以匹配一个数字,\w可以匹配一个字母或数字,所以: '00\d'可以匹配'007',但无法匹配'00A': '\d\d\d'可以匹 ...
- 深入解析Backbone.js框架的依赖库Underscore.js的作用
这篇文章主要介绍了深入解析Backbone.js框架的依赖库Underscore.js的作用,用过Node.js的朋友对Underscore一定不会陌生:)需要的朋友可以参考下 backbone必须依 ...
- 发布Hessian服务作为服务内部基础服务
摘要:Hessian经常作为服务内部RPC工具来使用,速度快效率高.重构代码的核心思想就是把共用的代码段提出来,使代码结构优化:架构设计类似,把基本的共用的服务提出来,使架构优化.下面讲述一下我在具体 ...
- 一个关于JSON的异常,获取List对象失败的。。。
重要的事情放在最前面,,以后不管遇到什么异常都一定要把异常读懂再想办法怎么解决,把异常读懂,异常读懂...... 这个异常我记得以前遇到过,而且好像已经做了笔记,,,,,今天翻了一下竟然没有,,,,, ...
- Python机器学习神器:sklearn&numpy
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdTAxMDE0MDMzOA==/font/5a6L5L2T/fontsize/400/fill/I0JBQk ...
- PHP-----TP框架基础
TP框架基础 把Thinkphp框架的压缩包解压到php文件夹下----www目录下. Thinkphp文件夹都有什么呢??? (所有用TP框架做的程序,要访问程序里面的网页.内容的话,全部要走这 ...
- HDU 1166 【线段树 || 树状数组,单点修改 维护区间和】
题目链接 HDU 1166 大概题意: 第一行一个整数T,表示有T组数据.每组数据第一行一个正整数N(N<=50000),表示敌人有N个工兵营地,接下来有N个正整数,第i个正整数ai代表第i个工 ...