简单了解python gevent 协程使用及作用


Posted in Python onJuly 22, 2019

简介

没有切换开销。因为子程序切换不是线程切换,而是由程序自身控制,没有线程切换的开销,因此执行效率高,

不需要锁机制。因为只有一个线程,也不存在同时写变量冲突,在协程中控制共享资源不加锁,只需要判断状态就好了,所以执行效率比多线程高很多

Python对协程的支持还非常有限,用在generator中的yield可以一定程度上实现协程。

yield

传统的生产者-消费者模型是一个线程写消息,一个线程取消息,通过锁机制控制队列和等待,但一不小心就可能死锁。

如果改用协程,生产者生产消息后,直接通过yield跳转到消费者开始执行,待消费者执行完毕后,切换回生产者继续生产,效率极高

代码

import time

def consumer():
  r = ''
  while True:
    n = yield r
    if not n:
      return
    print('[CONSUMER] Consuming %s....' % n)
    r = '200 OK'

def produce(c):
  c.next()
  n = 0
  while n < 5:
    n = n + 1
    print('[PRODUCER] Producing %s...' % n)
    r = c.send(n)
    print('[PRODUCER] Consumer return: %s\n' % r)
  c.close()

if __name__=='__main__':
  c = consumer()
  produce(c)

结果

[PRODUCER] Producing 1...
[CONSUMER] Consuming 1....
[PRODUCER] Consumer return: 200 OK

[PRODUCER] Producing 2...
[CONSUMER] Consuming 2....
[PRODUCER] Consumer return: 200 OK

[PRODUCER] Producing 3...
[CONSUMER] Consuming 3....
[PRODUCER] Consumer return: 200 OK

[PRODUCER] Producing 4...
[CONSUMER] Consuming 4....
[PRODUCER] Consumer return: 200 OK

[PRODUCER] Producing 5...
[CONSUMER] Consuming 5....
[PRODUCER] Consumer return: 200 OK

分析

  • 首先调用c.next()启动生成器
  • 然后,一旦生产了东西,通过c.send(n)切换到consumer执行
  • consumer通过yield拿到消息,处理,又通过yield把结果传回
  • produce拿到consumer处理的结果,继续生产下一条消息

整个过程无锁,由一个线程执行,producer和consumer写作完成任务,所以叫做协程

gevent

Python通过yield提供了对协程的基本支持,但是不完全。而第三方的gevent为Python提供了比较完善的协程支持

gevent是第三方库,通过greenlet实现协程,其基本思想是:

当一个greenlet遇到IO操作时(比如访问网络),就自动切换到其他的greenlet,等到IO操作完成,再在适当的时候切换回来继续执行。由于IO操作非常耗时,经常使程序处于等待状态,有了gevent为我们自动切换协程,就保证总有greenlet在运行,而不是等待IO。

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 0x7f7216efbe10: f(5)> 0
<Greenlet at 0x7f7216efbe10: f(5)> 1
<Greenlet at 0x7f7216efbe10: f(5)> 2
<Greenlet at 0x7f7216efbe10: f(5)> 3
<Greenlet at 0x7f7216efbe10: f(5)> 4
<Greenlet at 0x7f720f54e0f0: f(5)> 0
<Greenlet at 0x7f720f54e0f0: f(5)> 1
<Greenlet at 0x7f720f54e0f0: f(5)> 2
<Greenlet at 0x7f720f54e0f0: f(5)> 3
<Greenlet at 0x7f720f54e0f0: f(5)> 4
<Greenlet at 0x7f720f54e190: f(5)> 0
<Greenlet at 0x7f720f54e190: f(5)> 1
<Greenlet at 0x7f720f54e190: f(5)> 2
<Greenlet at 0x7f720f54e190: f(5)> 3
<Greenlet at 0x7f720f54e190: f(5)> 4

可以看出3个greenlet依次运行,而不是交替运行

要让greenlet交替运行,可以通过gevent.sleep()交出控制权

import gevent

def f(n):
  for i in range(n):
    print gevent.getcurrent(), i
    gevent.sleep(1)

g1 = gevent.spawn(f, 3)
g2 = gevent.spawn(f, 3)
g3 = gevent.spawn(f, 3)

g1.join()
g2.join()
g3.join()

结果

<Greenlet at 0x7f74e2179e10: f(3)> 0
<Greenlet at 0x7f74da7cb0f0: f(3)> 0
<Greenlet at 0x7f74da7cb190: f(3)> 0
<Greenlet at 0x7f74e2179e10: f(3)> 1
<Greenlet at 0x7f74da7cb0f0: f(3)> 1
<Greenlet at 0x7f74da7cb190: f(3)> 1
<Greenlet at 0x7f74e2179e10: f(3)> 2
<Greenlet at 0x7f74da7cb0f0: f(3)> 2
<Greenlet at 0x7f74da7cb190: f(3)> 2

可以看出3个greenlet是交替执行

如果把循环改为1000,让执行次数执行时间长些,查看进程,可以看到线程只有一个。

当然,实际代码中,不可能用gevent.sleep()去切换协程,而是在执行IO操作是,gevent自动切换,参考代码如下

import gevent
from gevent import monkey; monkey.patch_all()
import urllib2

def f(url):
  print 'GET: %s' % url
  resp = urllib2.urlopen(url)
  data = resp.read()
  print '[%d] bytes received from %s\n' %(len(data), url)

gevent.joinall([
gevent.spawn(f, 'http://www.cnblogs.com/kaituorensheng/'),
gevent.spawn(f, 'https://www.python.org/'),
gevent.spawn(f, 'https://www.baidu.com'),
])

执行结果

GET: http://www.cnblogs.com/kaituorensheng/
GET: https://www.python.org/
GET: https://www.baidu.com
[227] bytes received from https://www.baidu.com

[14667] bytes received from http://www.cnblogs.com/kaituorensheng/

[47348] bytes received from https://www.python.org/

可以看到3个url结束顺序并不是依次执行完的。


使用gevent,可以获得极高的并发性能,但gevent只能在Unix/Linux下运行,在Windows下不保证正常安装和运行。

由于gevent是基于IO切换的协程,所以最神奇的是,我们编写的Web App代码,不需要引入gevent的包,也不需要改任何代码,仅仅在部署的时候,用一个支持gevent的WSGI服务器,立刻就获得了数倍的性能提升。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python开发WebService系列教程之REST,web.py,eurasia,Django
Jun 30 Python
使用Python内置的模块与函数进行不同进制的数的转换
Mar 12 Python
Python升级导致yum、pip报错的解决方法
Sep 06 Python
Python探索之URL Dispatcher实例详解
Oct 28 Python
python实现BackPropagation算法
Dec 14 Python
matplotlib subplots 设置总图的标题方法
May 25 Python
Python2包含中文报错的解决方法
Jul 09 Python
python+pyqt5实现24点小游戏
Jan 24 Python
flask 框架操作MySQL数据库简单示例
Feb 02 Python
在python中求分布函数相关的包实例
Apr 15 Python
Python根据字符串调用函数过程解析
Nov 05 Python
Python基础之Socket通信原理
Apr 22 Python
利用Pandas和Numpy按时间戳将数据以Groupby方式分组
Jul 22 #Python
python+logging+yaml实现日志分割
Jul 22 #Python
python删除列表元素的三种方法(remove,pop,del)
Jul 22 #Python
python Gunicorn服务器使用方法详解
Jul 22 #Python
python实现按行分割文件
Jul 22 #Python
python UDP(udp)协议发送和接收的实例
Jul 22 #Python
linux环境下Django的安装配置详解
Jul 22 #Python
You might like
用PHP产生动态的影像图
2006/10/09 PHP
浅析HTTP消息头网页缓存控制以及header常用指令介绍
2013/06/28 PHP
PHP四舍五入精确小数位及取整
2014/01/14 PHP
php使用event扩展的io复用测试的示例
2020/10/20 PHP
在firefox和Chrome下关闭浏览器窗口无效的解决方法
2014/01/16 Javascript
jquery操作HTML5 的data-*的用法实例分享
2014/08/17 Javascript
jQuery实现炫酷的鼠标轨迹特效
2015/02/01 Javascript
浅谈JavaScript的Polymer框架中的behaviors对象
2015/07/29 Javascript
AngularJS中处理多个promise的方式
2016/02/02 Javascript
JavaScript实现写入文件到本地的方法【基于FileSaver.js插件】
2018/03/15 Javascript
再谈Angular4 脏值检测(性能优化)
2018/04/23 Javascript
安装vue-cli的简易过程
2018/05/22 Javascript
让webpack+vue-cil项目不再自动打开浏览器的方法
2018/09/27 Javascript
angularJs中orderBy筛选以及filter过滤数据的方法
2018/09/30 Javascript
layui当点击文本框时弹出选择框,显示选择内容的例子
2019/09/02 Javascript
浅谈Vue 函数式组件的使用技巧
2020/06/16 Javascript
Python中map和列表推导效率比较实例分析
2015/06/17 Python
VSCode下好用的Python插件及配置
2018/04/06 Python
Python对接支付宝支付自实现功能
2019/10/10 Python
python GUI库图形界面开发之PyQt5浏览器控件QWebEngineView详细使用方法
2020/02/26 Python
canvas进阶之贝塞尔公式推导与物体跟随复杂曲线的轨迹运动
2018/01/10 HTML / CSS
打造经典复古风格的品牌:Alice + Olivia(爱丽丝+奥利维亚)
2016/09/07 全球购物
德国宠物用品、宠物食品及水族馆网上商店:ZooRoyal
2017/07/09 全球购物
Chicco婴儿用品美国官网:汽车座椅、婴儿推车、高脚椅等
2018/11/05 全球购物
药学专业大学生自荐信
2013/09/28 职场文书
任课老师推荐信范文
2013/11/24 职场文书
食品行业求职人的自我评价
2014/01/19 职场文书
制药工程专业个人求职自荐信
2014/01/25 职场文书
大学生优秀自荐信范文
2014/02/25 职场文书
竞选团支书演讲稿
2014/04/28 职场文书
营销部内勤岗位职责
2014/04/30 职场文书
城管执法人员纪律作风整顿思想汇报
2014/09/13 职场文书
夫妻房产协议书的格式
2014/10/11 职场文书
大学生村官个人总结
2015/02/15 职场文书
2015年治庸问责工作总结
2015/07/27 职场文书
多线程Spring通过@Scheduled实现定时任务
2022/05/25 Java/Android