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返回昨天日期的方法
May 13 Python
Python中的多行注释文档编写风格汇总
Jun 16 Python
python3使用pyqt5制作一个超简单浏览器的实例
Oct 19 Python
Pandas实现数据类型转换的一些小技巧汇总
May 07 Python
python判断列表的连续数字范围并分块的方法
Nov 16 Python
python调用动态链接库的基本过程详解
Jun 19 Python
pymysql的简单封装代码实例
Jan 08 Python
利用Python脚本实现自动刷网课
Feb 03 Python
使用python的pyplot绘制函数实例
Feb 13 Python
Python使用plt.boxplot() 参数绘制箱线图
Jun 04 Python
通俗易懂了解Python装饰器原理
Sep 17 Python
Django框架中视图的用法
Jun 10 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实现的css文件背景图片下载器代码
2014/11/11 PHP
PHP实现在windows下配置sendmail并通过mail()函数发送邮件的方法
2017/06/20 PHP
php生出随机字符串
2017/07/06 PHP
父窗口获取弹出子窗口文本框的值
2006/06/27 Javascript
doctype后如何获得body.clientHeight的方法
2007/07/11 Javascript
JavaScript 事件系统
2010/07/22 Javascript
增强用户体验友好性之jquery easyui window 窗口关闭时的提示
2012/06/22 Javascript
jQuery-1.9.1源码分析系列(十一)DOM操作续之克隆节点
2015/12/01 Javascript
JS实现iframe自适应高度的方法示例
2017/01/07 Javascript
JS实现一个简单的日历
2017/02/22 Javascript
vue.js框架实现表单排序和分页效果
2017/08/09 Javascript
jQuery EasyUI Layout实现tabs标签的实例
2017/09/26 jQuery
webstorm和.vue中es6语法报错的解决方法
2018/05/08 Javascript
bootstrap table合并行数据并居中对齐效果
2018/10/17 Javascript
js遍历详解(forEach, map, for, for...in, for...of)
2019/08/28 Javascript
JavaScript实现省份城市的三级联动
2020/02/11 Javascript
vue实现给div绑定keyup的enter事件
2020/07/31 Javascript
vue 解决mintui弹窗弹起来,底部页面滚动bug问题
2020/11/12 Javascript
python求众数问题实例
2014/09/26 Python
Python中使用语句导入模块或包的机制研究
2015/03/30 Python
win10环境下python3.5安装步骤图文教程
2017/02/03 Python
python pandas 如何替换某列的一个值
2018/06/09 Python
python中的数组赋值与拷贝的区别详解
2019/11/26 Python
浅析python 定时拆分备份 nginx 日志的方法
2020/04/27 Python
python调用摄像头的示例代码
2020/09/28 Python
利用Opencv实现图片的油画特效实例
2021/02/28 Python
利用SVG和CSS3来实现一个炫酷的边框动画
2015/07/22 HTML / CSS
CSS3对背景图片的裁剪及尺寸和位置的设定方法
2016/03/07 HTML / CSS
使用layui框架实现点击左侧导航切换右侧内容且右侧选项卡跟随变化的效果
2020/11/10 HTML / CSS
存储过程和函数的区别
2013/05/28 面试题
生产现场工艺工程师岗位职责
2013/11/28 职场文书
鼓励运动员的广播稿
2014/02/08 职场文书
党风廉政建设责任书
2014/04/14 职场文书
明确岗位职责
2015/02/14 职场文书
jQuery实现广告显示和隐藏动画
2021/07/04 jQuery
详解Vue的列表渲染
2021/11/20 Vue.js