Python的gevent框架的入门教程


Posted in Python onApril 29, 2015

Python通过yield提供了对协程的基本支持,但是不完全。而第三方的gevent为Python提供了比较完善的协程支持。

gevent是第三方库,通过greenlet实现协程,其基本思想是:

当一个greenlet遇到IO操作时,比如访问网络,就自动切换到其他的greenlet,等到IO操作完成,再在适当的时候切换回来继续执行。由于IO操作非常耗时,经常使程序处于等待状态,有了gevent为我们自动切换协程,就保证总有greenlet在运行,而不是等待IO。

由于切换是在IO操作时自动完成,所以gevent需要修改Python自带的一些标准库,这一过程在启动时通过monkey patch完成:

from gevent import monkey; monkey.patch_socket()
import gevent

def f(n):
  for i in range(n):
    print gevent.getcurrent(), i

g1 = gevent.spawn(f, 5)
g2 = gevent.spawn(f, 5)
g3 = gevent.spawn(f, 5)
g1.join()
g2.join()
g3.join()

运行结果:

<Greenlet at 0x10e49f550: f(5)> 0
<Greenlet at 0x10e49f550: f(5)> 1
<Greenlet at 0x10e49f550: f(5)> 2
<Greenlet at 0x10e49f550: f(5)> 3
<Greenlet at 0x10e49f550: f(5)> 4
<Greenlet at 0x10e49f910: f(5)> 0
<Greenlet at 0x10e49f910: f(5)> 1
<Greenlet at 0x10e49f910: f(5)> 2
<Greenlet at 0x10e49f910: f(5)> 3
<Greenlet at 0x10e49f910: f(5)> 4
<Greenlet at 0x10e49f4b0: f(5)> 0
<Greenlet at 0x10e49f4b0: f(5)> 1
<Greenlet at 0x10e49f4b0: f(5)> 2
<Greenlet at 0x10e49f4b0: f(5)> 3
<Greenlet at 0x10e49f4b0: f(5)> 4

可以看到,3个greenlet是依次运行而不是交替运行。

要让greenlet交替运行,可以通过gevent.sleep()交出控制权:

def f(n):
  for i in range(n):
    print gevent.getcurrent(), i
    gevent.sleep(0)

执行结果:

<Greenlet at 0x10cd58550: f(5)> 0
<Greenlet at 0x10cd58910: f(5)> 0
<Greenlet at 0x10cd584b0: f(5)> 0
<Greenlet at 0x10cd58550: f(5)> 1
<Greenlet at 0x10cd584b0: f(5)> 1
<Greenlet at 0x10cd58910: f(5)> 1
<Greenlet at 0x10cd58550: f(5)> 2
<Greenlet at 0x10cd58910: f(5)> 2
<Greenlet at 0x10cd584b0: f(5)> 2
<Greenlet at 0x10cd58550: f(5)> 3
<Greenlet at 0x10cd584b0: f(5)> 3
<Greenlet at 0x10cd58910: f(5)> 3
<Greenlet at 0x10cd58550: f(5)> 4
<Greenlet at 0x10cd58910: f(5)> 4
<Greenlet at 0x10cd584b0: f(5)> 4

3个greenlet交替运行,

把循环次数改为500000,让它们的运行时间长一点,然后在操作系统的进程管理器中看,线程数只有1个。

当然,实际代码里,我们不会用gevent.sleep()去切换协程,而是在执行到IO操作时,gevent自动切换,代码如下:

from gevent import monkey; monkey.patch_all()
import gevent
import urllib2

def f(url):
  print('GET: %s' % url)
  resp = urllib2.urlopen(url)
  data = resp.read()
  print('%d bytes received from %s.' % (len(data), url))

gevent.joinall([
    gevent.spawn(f, 'https://www.python.org/'),
    gevent.spawn(f, 'https://www.yahoo.com/'),
    gevent.spawn(f, 'https://github.com/'),
])

运行结果:

GET: https://www.python.org/
GET: https://www.yahoo.com/
GET: https://github.com/
45661 bytes received from https://www.python.org/.
14823 bytes received from https://github.com/.
304034 bytes received from https://www.yahoo.com/.

从结果看,3个网络操作是并发执行的,而且结束顺序不同,但只有一个线程。
小结

使用gevent,可以获得极高的并发性能,但gevent只能在Unix/Linux下运行,在Windows下不保证正常安装和运行。

由于gevent是基于IO切换的协程,所以最神奇的是,我们编写的Web App代码,不需要引入gevent的包,也不需要改任何代码,仅仅在部署的时候,用一个支持gevent的WSGI服务器,立刻就获得了数倍的性能提升。具体部署方式可以参考后续“实战”-“部署Web App”一节。

Python 相关文章推荐
pyramid配置session的方法教程
Nov 27 Python
python批量修改文件后缀示例代码分享
Dec 24 Python
python抽象基类用法实例分析
Jun 04 Python
Python使用time模块实现指定时间触发器示例
May 18 Python
python字符串过滤性能比较5种方法
Jun 22 Python
Python WSGI的深入理解
Aug 01 Python
python模块之subprocess模块级方法的使用
Mar 26 Python
django将网络中的图片,保存成model中的ImageField的实例
Aug 07 Python
Python如何使用k-means方法将列表中相似的句子归类
Aug 08 Python
Django使用 Bootstrap 样式修改书籍列表过程解析
Aug 09 Python
Python3从零开始搭建一个语音对话机器人的实现
Aug 23 Python
python 窃取摄像头照片的实现示例
Jan 08 Python
在Python中使用HTML模版的教程
Apr 29 #Python
以Flask为例讲解Python的框架的使用方法
Apr 29 #Python
详解Python程序与服务器连接的WSGI接口
Apr 29 #Python
Python的SQLAlchemy框架使用入门
Apr 29 #Python
python使用post提交数据到远程url的方法
Apr 29 #Python
python实现根据ip地址反向查找主机名称的方法
Apr 29 #Python
连接Python程序与MySQL的教程
Apr 29 #Python
You might like
探讨PHP函数ip2long转换IP时数值太大产生负数的解决方法
2013/06/06 PHP
浅析PHP原理之变量(Variables inside PHP)
2013/08/09 PHP
PHP使用redis位图bitMap 实现签到功能
2019/10/08 PHP
javascript 学习笔记(六)浏览器类型及版本信息检测代码
2011/04/08 Javascript
Javascript中的this绑定介绍
2011/09/22 Javascript
jquery submit ie6下失效的原因分析及解决方法
2013/11/15 Javascript
页面加载完毕后滚动条自动滚动一定位置
2014/02/20 Javascript
jQuery获取动态生成的元素示例
2014/06/15 Javascript
用NODE.JS中的流编写工具是要注意的事项
2016/03/01 Javascript
微信小程序 开发工具快捷键整理
2016/10/31 Javascript
BootStrap按钮标签及基本样式
2016/11/23 Javascript
纯JS实现表单验证实例
2016/12/24 Javascript
angularJs的ng-class切换class
2017/06/23 Javascript
详解Vue2中组件间通信的解决全方案
2017/07/28 Javascript
ES6中javascript实现函数绑定及类的事件绑定功能详解
2017/11/08 Javascript
微信小程序 函数防抖 解决重复点击消耗性能问题实现代码
2019/09/12 Javascript
微信小程序实现多行文字超出部分省略号显示功能
2019/10/23 Javascript
Vue实现点击当前行变色
2020/12/14 Vue.js
ajax jquery实现页面某一个div的刷新效果
2021/03/04 jQuery
python 生成目录树及显示文件大小的代码
2009/07/23 Python
python写的ARP攻击代码实例
2014/06/04 Python
Python使用CMD模块更优雅的运行脚本
2015/05/11 Python
Python SQLite3数据库日期与时间常见函数用法分析
2017/08/14 Python
python实现指定文件夹下的指定文件移动到指定位置
2018/09/17 Python
python实现爬取百度图片的方法示例
2019/07/06 Python
python3注册全局热键的实现
2020/03/22 Python
python编写softmax函数、交叉熵函数实例
2020/06/11 Python
HTML5中input[type='date']自定义样式与日历校验功能的实现代码
2017/07/11 HTML / CSS
WoolOvers澳洲官方网站:英国针织服装公司
2018/05/13 全球购物
巴西手表购物网站:eclock
2019/03/19 全球购物
在加拿大在线租赁和购买电子游戏:Game Access
2019/09/02 全球购物
什么是View State?
2013/01/27 面试题
先进集体事迹材料
2014/02/17 职场文书
大学生实习鉴定评语
2014/04/25 职场文书
廉洁自律演讲稿
2014/05/22 职场文书
居委会四风问题个人对照检查材料
2014/09/25 职场文书