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判断、获取一张图片主色调的2个实例
Apr 10 Python
Python greenlet实现原理和使用示例
Sep 24 Python
go语言计算两个时间的时间差方法
Mar 13 Python
如何使用python爬取csdn博客访问量
Feb 14 Python
详解python中requirements.txt的一切
Mar 03 Python
python opencv实现运动检测
Jul 10 Python
Python倒排索引之查找包含某主题或单词的文件
Nov 13 Python
使用sklearn对多分类的每个类别进行指标评价操作
Jun 11 Python
tensorflow使用CNN分析mnist手写体数字数据集
Jun 17 Python
python基于openpyxl生成excel文件
Dec 23 Python
python实现经典排序算法的示例代码
Feb 07 Python
python 机器学习的标准化、归一化、正则化、离散化和白化
Apr 16 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
header中Content-Disposition的作用与使用方法
2012/06/13 PHP
PHP更新购物车数量(表单部分/PHP处理部分)
2013/05/03 PHP
php中函数前加&amp;符号的作用分解
2014/07/08 PHP
如何写php守护进程(Daemon)
2015/12/30 PHP
JS将表单导出成EXCEL的实例代码
2013/11/11 Javascript
JavaScript-RegExp对象只能使用一次问题解决方法
2014/06/23 Javascript
jquery控制显示服务器生成的图片流
2015/08/04 Javascript
javascript实现checkbox复选框实例代码
2016/01/10 Javascript
Javascript如何判断数据类型和数组类型
2016/06/22 Javascript
js倒计时小实例(多次定时)
2016/12/08 Javascript
Jquery Easyui菜单组件Menu使用详解(15)
2016/12/18 Javascript
ng-zorro-antd 入门初体验
2018/12/03 Javascript
vue2.0中set添加属性后视图不能更新的解决办法
2019/02/22 Javascript
微信小程序使用npm包的方法步骤
2019/08/13 Javascript
使用 Angular RouteReuseStrategy 缓存(路由)组件的实例代码
2019/11/01 Javascript
Vue页面切换和a链接的本质区别详解
2019/11/12 Javascript
[05:40]DOTA2荣耀之路6:Wings最后进攻
2018/05/30 DOTA
Python中的列表知识点汇总
2015/04/14 Python
Python类的动态修改的实例方法
2017/03/24 Python
python游戏地图最短路径求解
2019/01/16 Python
Python3.5 Pandas模块之Series用法实例分析
2019/04/23 Python
python+selenium实现简历自动刷新的示例代码
2019/05/20 Python
Python读取实时数据流示例
2019/12/02 Python
python转化excel数字日期为标准日期操作
2020/07/14 Python
浅析Python 字符编码与文件处理
2020/09/24 Python
利用Python函数实现一个万历表完整示例
2021/01/23 Python
PHP中如何使用Cookie
2015/10/28 面试题
会计专业自我鉴定
2014/02/10 职场文书
税务干部鉴定材料
2014/02/11 职场文书
小学清明节活动方案
2014/03/08 职场文书
《最大的麦穗》教学反思
2014/04/17 职场文书
活动主持人开场白
2015/05/28 职场文书
学前教育见习总结
2015/06/23 职场文书
八年级数学教学反思
2016/02/17 职场文书
Go语言带缓冲的通道实现
2021/04/26 Golang
PyTorch中的torch.cat简单介绍
2022/03/17 Python