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处理json字符串转化为字典的简单实现
Jul 07 Python
python负载均衡的简单实现方法
Feb 04 Python
Python Cookie 读取和保存方法
Dec 28 Python
Python安装selenium包详细过程
Jul 23 Python
python使用Thread的setDaemon启动后台线程教程
Apr 25 Python
python删除指定列或多列单个或多个内容实例
Jun 28 Python
python 使用多线程创建一个Buffer缓存器的实现思路
Jul 02 Python
Python 在局部变量域中执行代码
Aug 07 Python
利用python3筛选excel中特定的行(行值满足某个条件/行值属于某个集合)
Sep 04 Python
python如何控制进程或者线程的个数
Oct 16 Python
如何在scrapy中集成selenium爬取网页的方法
Nov 18 Python
tensorflow学习笔记之tfrecord文件的生成与读取
Mar 31 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 substr,mb_substr以及mb_strcut的区别和用法
2013/06/21 PHP
PHP判断IP并转跳到相应城市分站的方法
2015/03/25 PHP
php反序列化长度变化尾部字符串逃逸(0CTF-2016-piapiapia)
2020/02/15 PHP
javascript在一段文字中的光标处插入其他文字
2007/08/26 Javascript
避免 showModalDialog 弹出新窗体的原因分析
2010/05/31 Javascript
修复ie8&amp;chrome下window的resize事件多次执行
2011/10/20 Javascript
Javascript HTML5 Canvas实现的一个画板
2020/04/12 Javascript
vuejs在解析时出现闪烁的原因及防止闪烁的方法
2016/09/19 Javascript
AngularJS实现自定义指令与控制器数据交互的方法示例
2017/06/19 Javascript
Vuex利用state保存新闻数据实例
2017/06/28 Javascript
原生js实现淘宝放大镜效果
2020/10/28 Javascript
tsconfig.json配置详解
2019/05/17 Javascript
vue-cli配置flexible过程详解
2019/07/04 Javascript
[05:03]显微镜下的DOTA2第十期——Ti3豪之超神幽鬼
2014/06/23 DOTA
[01:03:00]DOTA2上海特级锦标赛A组败者赛 EHOME VS CDEC第一局
2016/02/25 DOTA
简单谈谈python中的语句和语法
2017/08/10 Python
Python基于正则表达式实现检查文件内容的方法【文件检索】
2017/08/30 Python
解析Python中的eval()、exec()及其相关函数
2017/12/20 Python
Python实现随机漫步功能
2018/07/09 Python
django自定义模板标签过程解析
2019/12/14 Python
利用pytorch实现对CIFAR-10数据集的分类
2020/01/14 Python
python scatter函数用法实例详解
2020/02/11 Python
python实现udp传输图片功能
2020/03/20 Python
使用jupyter Nodebook查看函数或方法的参数以及使用情况
2020/04/14 Python
Python日志:自定义输出字段 json格式输出方式
2020/04/27 Python
浅谈matplotlib 绘制梯度下降求解过程
2020/07/12 Python
Ubuntu20.04环境安装tensorflow2的方法步骤
2021/01/29 Python
CSS3打造百度贴吧的3D翻牌效果示例
2017/01/04 HTML / CSS
您在慕尼黑的跑步商店:Lauf-bar
2019/10/11 全球购物
斯洛伐克电子产品购物网站:DATART
2020/04/05 全球购物
波兰运动鞋网上商店:Distance.pl
2020/07/30 全球购物
声明struct x1 { . . . }; 和typedef struct { . . . }x2;有什么不同
2012/06/02 面试题
2014年财务人员工作总结
2014/11/11 职场文书
2015年测量员工作总结
2015/05/23 职场文书
Pandas||过滤缺失数据||pd.dropna()函数的用法说明
2021/05/14 Python
PHP使用QR Code生成二维码实例
2021/07/07 PHP