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 相关文章推荐
Django集成百度富文本编辑器uEditor攻略
Jul 04 Python
python中使用百度音乐搜索的api下载指定歌曲的lrc歌词
Jul 18 Python
python实现带验证码网站的自动登陆实现代码
Jan 12 Python
Python编程实现控制cmd命令行显示颜色的方法示例
Aug 14 Python
Python numpy生成矩阵、串联矩阵代码分享
Dec 04 Python
python 删除指定时间间隔之前的文件实例
Apr 24 Python
redis之django-redis的简单缓存使用
Jun 07 Python
使用EduBlock轻松学习Python编程
Oct 08 Python
Python计算两个矩形重合面积代码实例
Sep 16 Python
python 3.7.4 安装 opencv的教程
Oct 10 Python
python中bytes和str类型的区别
Oct 21 Python
基于plt.title无法显示中文的快速解决
May 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
Oracle 常见问题解答
2006/10/09 PHP
CodeIgniter删除和设置Cookie的方法
2015/04/07 PHP
php实现window平台的checkdnsrr函数
2015/05/27 PHP
Zend Framework框架路由机制代码分析
2016/03/22 PHP
Prototype使用指南之base.js
2007/01/10 Javascript
用JavaScript实现仿Windows关机效果
2007/03/10 Javascript
JMenuTab简单使用说明
2008/03/13 Javascript
node.js实现爬虫教程
2020/08/25 Javascript
再谈Javascript中的基本类型和引用类型(推荐)
2016/07/01 Javascript
Bootstrap表单布局
2016/07/19 Javascript
标准的js无缝滚动效果
2016/08/30 Javascript
使用纯JS代码判断字符串中有多少汉字的实现方法(超简单实用)
2016/11/12 Javascript
jQuery实现百度登录框的动态切换效果
2017/04/21 jQuery
详解如何使用vue-cli脚手架搭建Vue.js项目
2017/05/19 Javascript
jQuery ajax读取本地json文件的实例
2017/10/31 jQuery
详解vue-cli 接口代理配置
2017/12/13 Javascript
解决Vue打包之后文件路径出错的问题
2018/03/06 Javascript
详解Vue结合后台的列表增删改案例
2018/08/21 Javascript
React 源码中的依赖注入方法
2018/11/07 Javascript
javascript实现导航栏分页效果
2019/06/27 Javascript
基于 vue-skeleton-webpack-plugin 的骨架屏实战
2019/08/05 Javascript
js DOM的事件常见操作实例详解
2019/12/16 Javascript
vue-cli+webpack项目打包到服务器后,ttf字体找不到的解决操作
2020/08/28 Javascript
浅谈Python 对象内存占用
2016/07/15 Python
python实现数据图表
2017/07/29 Python
Python实现图片尺寸缩放脚本
2018/03/10 Python
Python实现带参数的用户验证功能装饰器示例
2018/12/14 Python
Python配置虚拟环境图文步骤
2019/05/20 Python
python thrift 实现 单端口多服务的过程
2020/06/08 Python
Python列表的深复制和浅复制示例详解
2021/02/12 Python
地球一小时倡议书
2014/04/15 职场文书
舞蹈兴趣小组活动总结
2014/07/07 职场文书
大学生安全责任书
2014/07/25 职场文书
邀请函范文
2015/02/02 职场文书
我的生日感言
2015/08/03 职场文书
比较几种Redis集群方案
2021/06/21 Redis