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使用beautifulsoup从爱奇艺网抓取视频播放
Jan 23 Python
python中的全局变量用法分析
Jun 09 Python
Python制作简单的网页爬虫
Nov 22 Python
详解Python3的TFTP文件传输
Jun 26 Python
浅谈PYTHON 关于文件的操作
Mar 19 Python
Python函数装饰器常见使用方法实例详解
Mar 30 Python
Python3 tkinter 实现文件读取及保存功能
Sep 12 Python
通过实例了解Python str()和repr()的区别
Jan 17 Python
浅谈Python3多线程之间的执行顺序问题
May 02 Python
什么是Python中的顺序表
Jun 02 Python
python操作微信自动发消息的实现(微信聊天机器人)
Jul 14 Python
Python打包exe时各种异常处理方案总结
May 18 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
帅气的琦玉老师
2020/03/02 日漫
PHP has encountered an Access Violation
2007/01/15 PHP
PHP开启gzip页面压缩实例代码
2010/03/11 PHP
浅析php原型模式
2014/11/25 PHP
PHP翻页跳转功能实现方法
2020/11/30 PHP
PHP实现八皇后算法
2019/05/06 PHP
JS 分号引起的一段调试问题
2009/06/18 Javascript
[JSF]使用DataModel处理表行事件的实例代码
2013/08/05 Javascript
JavaScript中的this到底是什么(一)
2015/12/09 Javascript
Javascript对象字面量的理解
2016/06/22 Javascript
Jquery实现跨域异步上传文件总结
2017/02/03 Javascript
详解vue-router 2.0 常用基础知识点之导航钩子
2017/05/10 Javascript
详解在Vue中有条件地使用CSS类
2017/09/30 Javascript
jquery实现楼层滚动效果
2018/01/01 jQuery
webpack自动打包和热更新的实现方法
2019/06/24 Javascript
python通过字典dict判断指定键值是否存在的方法
2015/03/21 Python
从源码解析Python的Flask框架中request对象的用法
2016/06/02 Python
Python在for循环中更改list值的方法【推荐】
2018/08/17 Python
python3实现爬取淘宝美食代码分享
2018/09/23 Python
在python中将list分段并保存为array类型的方法
2019/07/15 Python
Django中Middleware中的函数详解
2019/07/18 Python
用Python将Excel数据导入到SQL Server的例子
2019/08/24 Python
wxPython实现整点报时
2019/11/18 Python
python实现的分析并统计nginx日志数据功能示例
2019/12/21 Python
Python xml、字典、json、类四种数据类型如何实现互相转换
2020/05/27 Python
如何在python中实现线性回归
2020/08/10 Python
python实现企业微信定时发送文本消息的示例代码
2020/11/24 Python
Python使用Turtle模块绘制国旗的方法示例
2021/02/28 Python
6种非常炫酷的CSS3按钮边框动画特效
2016/03/16 HTML / CSS
HTML5移动端开发遇见的东西
2019/10/11 HTML / CSS
详解前端HTML5几种存储方式的总结
2016/12/27 HTML / CSS
莫斯科的韩国化妆品店:Sifo
2019/12/04 全球购物
幼儿园保育员岗位职责
2014/04/13 职场文书
2014年销售经理工作总结
2014/12/01 职场文书
新学期小学班主任工作计划
2019/06/21 职场文书
Golang流模式之grpc的四种数据流
2022/04/13 Golang