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 相关文章推荐
Python3.x和Python2.x的区别介绍
Feb 12 Python
Python中使用scapy模拟数据包实现arp攻击、dns放大攻击例子
Oct 23 Python
Python实现堡垒机模式下远程命令执行操作示例
May 09 Python
python实现点击按钮修改数据的方法
Jul 17 Python
Python综合应用名片管理系统案例详解
Jan 03 Python
pycharm快捷键汇总
Feb 14 Python
python GUI库图形界面开发之PyQt5滑块条控件QSlider详细使用方法与实例
Feb 28 Python
Python2 与Python3的版本区别实例分析
Mar 30 Python
pandas的resample重采样的使用
Apr 24 Python
python多线程实现同时执行两个while循环的操作
May 02 Python
Python通过队列来实现进程间通信的示例
Oct 14 Python
用 Python 元类的特性实现 ORM 框架
May 19 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实现从ftp服务器上下载文件树到本地电脑的程序
2009/02/10 PHP
匹配csdn用户数据库与官方用户的重合度并将重叠部分的用户筛选出来
2011/12/25 PHP
php ctype函数中文翻译和示例
2014/03/21 PHP
PHP实现在数据库百万条数据中随机获取20条记录的方法
2017/04/19 PHP
PHP使用openssl扩展实现加解密方法示例
2020/02/20 PHP
JS定时刷新页面及跳转页面的方法
2013/07/04 Javascript
node.js中的fs.appendFileSync方法使用说明
2014/12/17 Javascript
谈谈AngularJs中的隐藏和显示
2015/12/09 Javascript
不得不分享的JavaScript常用方法函数集(下)
2015/12/25 Javascript
json对象与数组以及转换成js对象的简单实现方法
2016/06/24 Javascript
基于JavaScript实现随机颜色输入框
2016/12/10 Javascript
纯原生js实现table表格的增删
2017/01/05 Javascript
详解angular中的作用域及继承
2017/05/31 Javascript
nodejs 十六进制字符串型数据与btye型数据相互转换
2018/07/30 NodeJs
微信小程序 如何保持登录状态
2019/08/16 Javascript
NodeJS配置CORS实现过程详解
2020/12/02 NodeJs
[53:03]Optic vs TNC 2018国际邀请赛小组赛BO2 第一场 8.17
2018/08/18 DOTA
Python3 queue队列模块详细介绍
2018/01/05 Python
Python 元类实例解析
2018/04/04 Python
PyQt5实现下载进度条效果
2018/04/19 Python
python对象与json相互转换的方法
2019/05/07 Python
使用jupyter notebook运行python和R的步骤
2020/08/13 Python
用Python制作mini翻译器的实现示例
2020/08/17 Python
使用html5 canvas创建太空游戏的示例
2014/05/08 HTML / CSS
cosme官方海外旗舰店:日本最大化妆品和美容产品的综合口碑网站
2017/01/18 全球购物
美国最大的在线水培用品商店:GrowersHouse.com
2018/08/14 全球购物
类的核心特性有哪些
2014/01/01 面试题
初级软件工程师面试题 Junior Software Engineer Interview
2015/02/15 面试题
大四学年自我鉴定
2013/11/13 职场文书
《桂花雨》教学反思
2014/04/12 职场文书
医学生求职信
2014/07/01 职场文书
2015年行政助理工作总结
2015/04/30 职场文书
安全教育主题班会教案
2015/08/12 职场文书
手把手教你用SpringBoot将文件打包成zip存放或导出
2021/06/11 Java/Android
python基础之类属性和实例属性
2021/10/24 Python
DIY胆机必读:各国电子管评价
2022/04/06 无线电