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中的Django框架中进行字符串翻译
Jul 27 Python
Python引用模块和查找模块路径
Mar 17 Python
Python使用Scrapy爬虫框架全站爬取图片并保存本地的实现代码
Mar 04 Python
python 读取txt中每行数据,并且保存到excel中的实例
Apr 29 Python
Python 读写文件的操作代码
Sep 20 Python
Python 迭代,for...in遍历,迭代原理与应用示例
Oct 12 Python
django xadmin action兼容自定义model权限教程
Mar 30 Python
keras模型保存为tensorflow的二进制模型方式
May 25 Python
Python新手学习装饰器
Jun 04 Python
基于python requests selenium爬取excel vba过程解析
Aug 12 Python
Python基础之教你怎么在M1系统上使用pandas
May 08 Python
Python绘画好看的星空图
Mar 17 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
WordPress的文章自动添加关键词及关键词的SEO优化
2016/03/01 PHP
浅谈php中urlencode与rawurlencode的区别
2016/09/05 PHP
CakePHP框架Model关联对象用法分析
2017/08/04 PHP
thinkPHP框架自动填充原理与用法分析
2018/04/03 PHP
PHP基于DateTime类解决Unix时间戳与日期互转问题【针对1970年前及2038年后时间戳】
2018/06/13 PHP
地震发生中逃生十大法则
2008/05/12 Javascript
JavaScript 语言的递归编程
2010/05/18 Javascript
jQuery的deferred对象使用详解
2011/08/20 Javascript
ie中js创建checkbox默认选中问题探讨
2013/10/21 Javascript
JS获取随机数函数可自定义最小值最大值
2014/05/08 Javascript
jQuery中hide()方法用法实例
2014/12/24 Javascript
jQuery中的pushStack实现原理和应用实例
2015/02/03 Javascript
js判断某个字符出现的次数的简单实例
2016/06/03 Javascript
微信小程序实现实时圆形进度条的方法示例
2017/02/24 Javascript
详解Vue 事件修饰符capture 的使用
2017/12/29 Javascript
es6中使用map简化复杂条件判断操作实例详解
2020/02/19 Javascript
extjs图表绘制之条形图实现方法分析
2020/03/06 Javascript
[56:42]完美世界DOTA2联赛循环赛 Matador vs Forest 第二场 11.06
2020/11/06 DOTA
Python实现自动添加脚本头信息的示例代码
2016/09/02 Python
HTML5 常见面试题之PC端和移动端区别介绍
2018/01/22 HTML / CSS
美国知名的女性服饰品牌:LOFT(洛芙特)
2016/08/05 全球购物
《小石潭记》教学反思
2014/02/13 职场文书
2014元旦晚会策划方案
2014/02/19 职场文书
公司财务流程之主管工作流程
2014/03/03 职场文书
cf收人广告词
2014/03/14 职场文书
捐款倡议书格式范文
2014/05/14 职场文书
档案工作汇报材料
2014/08/21 职场文书
教代会开幕词
2015/01/28 职场文书
2014年度个人总结范文
2015/03/09 职场文书
大学生自我推荐信范文
2015/03/24 职场文书
小学生心理健康活动总结
2015/05/08 职场文书
驳回起诉民事裁定书
2015/05/19 职场文书
闪闪红星观后感
2015/06/08 职场文书
小学入学感言
2015/08/01 职场文书
高中生物教学反思
2016/02/20 职场文书
Python中字符串对象语法分享
2022/02/24 Python