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 相关文章推荐
python中的文件打开与关闭操作命令介绍
Apr 26 Python
python实现简单的单变量线性回归方法
Nov 08 Python
Python2和Python3之间的str处理方式导致乱码的讲解
Jan 03 Python
在Pycharm中对代码进行注释和缩进的方法详解
Jan 20 Python
python实现集中式的病毒扫描功能详解
Jul 09 Python
Python占用的内存优化教程
Jul 28 Python
详解Python Matplotlib解决绘图X轴值不按数组排序问题
Aug 05 Python
python实现高斯(Gauss)迭代法的例子
Nov 20 Python
Python如何访问字符串中的值
Feb 09 Python
利用Python制作动态排名图的实现代码
Apr 09 Python
python和php哪个更适合写爬虫
Jun 22 Python
如何利用python 读取配置文件
Jan 06 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批量生成缩略图的代码
2008/07/19 PHP
php中修改浏览器的User-Agent来伪装你的浏览器和操作系统
2011/07/29 PHP
PHP遍历数组的方法汇总
2015/04/30 PHP
php使用glob函数遍历文件和目录详解
2016/09/23 PHP
jquery 操作css样式、位置、尺寸方法汇总
2014/11/28 Javascript
JQuery标签页效果的两个实例讲解(4)
2015/09/17 Javascript
BootStrap的table表头固定tbody滚动的实例代码
2016/08/24 Javascript
discuz表情的JS提取方法分析
2017/03/22 Javascript
基于jQuery实现瀑布流页面
2017/04/11 jQuery
Vue.js学习教程之列表渲染详解
2017/05/17 Javascript
JavaScript运动框架 解决防抖动问题、悬浮对联(二)
2017/05/17 Javascript
dropload.js插件下拉刷新和上拉加载使用详解
2017/10/20 Javascript
3分钟了解vue数据劫持的原理实现
2019/05/01 Javascript
jquery实现选项卡切换代码实例
2019/05/14 jQuery
微信小程序实现星星评分效果
2020/11/01 Javascript
Vue 简单实现前端权限控制的示例
2020/12/25 Vue.js
Python使用urllib模块的urlopen超时问题解决方法
2014/11/08 Python
使用PyCharm配合部署Python的Django框架的配置纪实
2015/11/19 Python
vue.js实现输入框输入值内容实时响应变化示例
2018/07/07 Python
对Python函数设计规范详解
2019/07/19 Python
Keras 利用sklearn的ROC-AUC建立评价函数详解
2020/06/15 Python
Python如何在bool函数中取值
2020/09/21 Python
button在IE6/7下的黑边去除方案
2012/12/24 HTML / CSS
Vilebrequin欧洲官网:法国豪华泳装品牌(男士沙滩裤)
2018/04/14 全球购物
为有想象力的人提供的生活方式商店:Firebox
2018/06/04 全球购物
英国电信商店:BT Shop
2019/12/17 全球购物
电脑教师的教学自我评价
2013/11/26 职场文书
平面网站制作专科生的自我评价分享
2013/12/11 职场文书
英语专业学生个人求职信范文
2014/01/06 职场文书
热爱祖国的演讲稿
2014/05/04 职场文书
班主任开场白
2015/06/01 职场文书
导游词之青城山景区
2019/09/27 职场文书
matplotlib画混淆矩阵与正确率曲线的实例代码
2021/06/01 Python
php去除deprecated的实例方法
2021/11/17 PHP
教你部署vue项目到docker
2022/04/05 Vue.js
阿里云服务器Ubuntu 20.04上安装Odoo 15
2022/05/20 Servers