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中使用列表生成式的教程
Apr 27 Python
Python 实现文件的全备份和差异备份详解
Dec 27 Python
深入解答关于Python的11道基本面试题
Apr 01 Python
Python多进程并发与多线程并发编程实例总结
Feb 08 Python
DataFrame中去除指定列为空的行方法
Apr 08 Python
实例讲解Python脚本成为Windows中运行的exe文件
Jan 24 Python
python抓取搜狗微信公众号文章
Apr 01 Python
python爬虫基础教程:requests库(二)代码实例
Apr 09 Python
python 下载m3u8视频的示例代码
Nov 11 Python
Django model class Meta原理解析
Nov 14 Python
python 下载文件的几种方法汇总
Jan 06 Python
用python自动生成日历
Apr 24 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连接access数据库
2008/03/27 PHP
保存到桌面、设为桌面且带图标的PHP代码
2013/11/19 PHP
分享一则PHP定义函数代码
2015/02/26 PHP
js 静态动态成员 and 信息的封装和隐藏
2011/05/29 Javascript
js数组的基本用法及数组根据下标(数值或字符)移除元素
2013/10/20 Javascript
JS组件Bootstrap Table使用实例分享
2016/05/30 Javascript
基于MVC+EasyUI的web开发框架之使用云打印控件C-Lodop打印页面或套打报关运单信息
2016/08/29 Javascript
基于Bootstrap仿淘宝分页控件实现代码
2016/11/07 Javascript
jQuery实现点击下拉框中的值累加到文本框中的方法示例
2017/10/28 jQuery
JS实现方形抽奖效果
2018/08/27 Javascript
关于RxJS Subject的学习笔记
2018/12/05 Javascript
Vue项目中配置pug解析支持
2019/05/10 Javascript
简述vue-cli中chainWebpack的使用方法
2019/07/30 Javascript
layui中select,radio设置不生效的解决方法
2019/09/05 Javascript
JS 逻辑判断不要只知道用 if-else 和 switch条件判断(小技巧)
2020/05/27 Javascript
在Python中使用pngquant压缩png图片的教程
2015/04/09 Python
解读Django框架中的低层次缓存API
2015/07/24 Python
Python编码爬坑指南(必看)
2016/06/10 Python
Python爬取京东的商品分类与链接
2016/08/26 Python
flask中的wtforms使用方法
2018/07/21 Python
Python学习笔记之Break和Continue用法分析
2019/08/14 Python
python打造爬虫代理池过程解析
2019/08/15 Python
Tensorflow实现多GPU并行方式
2020/02/03 Python
python多进程 主进程和子进程间共享和不共享全局变量实例
2020/04/25 Python
python百行代码自制电脑端网速悬浮窗的实现
2020/05/12 Python
CSS3中的display:grid,网格布局介绍
2019/10/30 HTML / CSS
微信浏览器左上角返回按钮拦截功能
2017/11/21 HTML / CSS
英国健身仓库:Bodybuilding Warehouse
2019/03/06 全球购物
机关门卫岗位职责
2013/12/30 职场文书
某集团股份有限公司委托书样本
2014/09/24 职场文书
基层党支部整改方案
2014/10/25 职场文书
婚前协议书范本
2014/10/27 职场文书
办公室主任个人总结
2015/02/28 职场文书
幼儿园班级工作总结2015
2015/05/25 职场文书
Java面试题冲刺第十七天--基础篇3
2021/08/07 面试题
Java基础——Map集合
2022/04/01 Java/Android