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实现文件路径和url相互转换的方法
Jul 06 Python
Python基于pygame实现图片代替鼠标移动效果
Nov 11 Python
python爬虫使用cookie登录详解
Dec 27 Python
Python实现读取txt文件中的数据并绘制出图形操作示例
Feb 26 Python
使用matplotlib中scatter方法画散点图
Mar 19 Python
python binascii 进制转换实例
Jun 12 Python
Django urls.py重构及参数传递详解
Jul 23 Python
pandas中遍历dataframe的每一个元素的实现
Oct 23 Python
详解字符串在Python内部是如何省内存的
Feb 03 Python
如何基于python把文字图片写入word文档
Jul 31 Python
8种常用的Python工具
Aug 05 Python
Pandas自定义选项option设置
Jul 25 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读写文件的方法(生成HTML)
2006/11/27 PHP
dedecms采集中可以过滤多行代码的正则表达式
2007/03/17 PHP
php下使用curl模拟用户登陆的代码
2010/09/10 PHP
shopex中集成的站长统计功能的代码简单分析
2011/08/11 PHP
简单的php文件上传(实例)
2013/10/27 PHP
一个经典的PHP文件上传类分享
2014/11/18 PHP
Codeigniter发送邮件的方法
2015/03/19 PHP
PHP格式化MYSQL返回float类型的方法
2016/03/30 PHP
php文件包含目录配置open_basedir的使用与性能详解
2017/04/03 PHP
PHP面向对象程序设计子类扩展父类(子类重新载入父类)操作详解
2019/06/14 PHP
javascript Demo模态窗口
2009/12/06 Javascript
关于window.pageYOffset和document.documentElement.scrollTop
2011/04/05 Javascript
JS操作select下拉框动态变动(创建/删除/获取)
2013/06/02 Javascript
javascript生成随机颜色示例代码
2014/05/05 Javascript
script标签属性用type还是language
2015/01/21 Javascript
全面解析Bootstrap表单使用方法(表单控件)
2015/11/24 Javascript
Vue 2.0的数据依赖实现原理代码简析
2017/07/10 Javascript
JavaScript实现预览本地上传图片功能完整示例
2019/03/08 Javascript
如何在微信小程序中存setStorage
2019/12/13 Javascript
vue-以文件流-blob-的形式-下载-导出文件操作
2020/08/07 Javascript
vue 判断两个时间插件结束时间必选大于开始时间的代码
2020/11/04 Javascript
[03:20]2015国际邀请赛全明星表演赛
2015/08/08 DOTA
[27:08]完美世界DOTA2联赛PWL S2 SZ vs Rebirth 第二场 11.21
2020/11/23 DOTA
Python数据结构之Array用法实例
2014/10/09 Python
Python和JavaScript间代码转换的4个工具
2016/02/22 Python
Python实现自动添加脚本头信息的示例代码
2016/09/02 Python
Django如何开发简单的查询接口详解
2019/05/17 Python
Python动态参数/命名空间/函数嵌套/global和nonlocal
2019/05/29 Python
Python解压 rar、zip、tar文件的方法
2019/11/19 Python
利用Python制作动态排名图的实现代码
2020/04/09 Python
Selenium关闭INFO:CONSOLE提示的解决
2020/12/07 Python
瑞典的玛丽小姐:Miss Mary of Sweden
2019/02/13 全球购物
教师的实习鉴定
2013/12/15 职场文书
光信息科学与技术专业职业生涯规划
2014/03/13 职场文书
二手房购房意向书
2015/05/09 职场文书
kubernetes集群搭建Zabbix监控平台的详细过程
2022/07/07 Servers