python gevent 协程
简介
- 没有切换开销。因为子程序切换不是线程切换,而是由程序自身控制,没有线程切换的开销,因此执行效率高,
- 不需要锁机制。因为只有一个线程,也不存在同时写变量冲突,在协程中控制共享资源不加锁,只需要判断状态就好了,所以执行效率比多线程高很多
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 gevent 协程的更多相关文章
- Python Gevent协程自动切换IO
Gevent Gevent 是一个第三方库,可以轻松通过gevent实现并发同步或异步编程,在gevent中用到的主要模式是Greenlet, 它是以C扩展模块形式接入Python的轻量级协程. Gr ...
- python gevent(协程模块)
Python通过yield提供了对协程的基本支持,但是不完全.而第三方的gevent为Python提供了比较完善的协程支持. gevent是第三方库,通过greenlet实现协程,其基本思想是: 当一 ...
- python gevent协程
安装 pip install gevent import gevent from gevent import monkey monkey.patch_all()#捕捉所有阻塞,不止接收gevent.s ...
- Python之路-python(Queue队列、进程、Gevent协程、Select\Poll\Epoll异步IO与事件驱动)
一.进程: 1.语法 2.进程间通讯 3.进程池 二.Gevent协程 三.Select\Poll\Epoll异步IO与事件驱动 一.进程: 1.语法 简单的启动线程语法 def run(name): ...
- {python之协程}一 引子 二 协程介绍 三 Greenlet 四 Gevent介绍 五 Gevent之同步与异步 六 Gevent之应用举例一 七 Gevent之应用举例二
python之协程 阅读目录 一 引子 二 协程介绍 三 Greenlet 四 Gevent介绍 五 Gevent之同步与异步 六 Gevent之应用举例一 七 Gevent之应用举例二 一 引子 本 ...
- python之协程gevent模块
Gevent官网文档地址:http://www.gevent.org/contents.html 进程.线程.协程区分 我们通常所说的协程Coroutine其实是corporate routine的缩 ...
- python并发编程之gevent协程(四)
协程的含义就不再提,在py2和py3的早期版本中,python协程的主流实现方法是使用gevent模块.由于协程对于操作系统是无感知的,所以其切换需要程序员自己去完成. 系列文章 python并发编程 ...
- Python进阶----异步同步,阻塞非阻塞,线程池(进程池)的异步+回调机制实行并发, 线程队列(Queue, LifoQueue,PriorityQueue), 事件Event,线程的三个状态(就绪,挂起,运行) ,***协程概念,yield模拟并发(有缺陷),Greenlet模块(手动切换),Gevent(协程并发)
Python进阶----异步同步,阻塞非阻塞,线程池(进程池)的异步+回调机制实行并发, 线程队列(Queue, LifoQueue,PriorityQueue), 事件Event,线程的三个状态(就 ...
- Python (九) 协程以及数据库操作
本节内容 Gevent协程 Select\Poll\Epoll异步IO与事件驱动 Python连接Mysql数据库操做 Paramiko SSH 协程 协程,又称微线程,纤程.英文名Coroutine ...
随机推荐
- 解决VS+opencv中Debug版本与Release版本lib切换的问题
Author: Maddock Date: 2015-03-26 09:34:48 问题来源:http://bbs.csdn.net/topics/390733725 PS: 按照上述方法做的时候,在 ...
- 如何使用scikit—learn处理文本数据
答案在这里:http://www.tuicool.com/articles/U3uiiu http://scikit-learn.org/stable/modules/feature_extracti ...
- IOC装配Bean(XML方式)
Spring框架Bean实例化的方式 提供了三种方式实例化Bean 构造方法实例化(默认无参数,用的最多) 静态工厂实例化 实例工厂实例化 无参数构造方法的实例化 <!-- 默认情况下使用的就是 ...
- MySQL - 问题集 - "Waiting for table metadata lock"(待完善)
待完善.show processlist; 可参考1:http://blog.csdn.net/huochuangchuang/article/details/49423893 可参考2:http:/ ...
- 【CentOS】磁盘管理与vim编译器
一.查看硬盘或目录容量 1.df [-hmkiT] -h 查看系统磁盘使用情况 -m 使用MBytes显示结果 -k 使用KBytes显示结果 -i 查看inode -T 查看Type 2 ...
- php 冒泡 快速 选择 插入算法 四种基本算法
php四种基础算法:冒泡,选择,插入和快速排序法 来源:PHP100中文网 | 时间:2013-10-29 15:24:57 | 阅读数:120854 [导读] 许多人都说 算法是程序的核心,一个程序 ...
- jQuery的.bind()、.live()和.delegate()之间区别
摘要:jQuery的.bind()..live()和.delegate()之间的区别并非总是那么明显的,然而,如果我们对所有的不同之处都有清晰的理解的话,那么这将会有助于我们编写出更加简洁的代码,以及 ...
- NOIP2013D1T3货车运输
题目链接:http://www.luogu.org/problem/show?pid=1967 数据:http://www.cnblogs.com/wanglichao/p/5592058.html ...
- iOS常用技术
1.判断系统 #define UMSYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersi ...
- ZeroMQ接口函数之 :zmq_ctx_destroy - 销毁一个ZMQ环境上下文
ZeroMQ 官方地址 :http://api.zeromq.org/4-0:zmq_ctx_destroy zmq_ctx_destroy(3) ØMQ Manual - ØMQ/3.2.5 Nam ...