前言:gevent是python的一个并发框架,以微线程greenlet为核心,使用了epoll事件监听机制以及诸多其他优化而变得高效.而且其中有个monkey类,

将现有基于Python线程直接转化为greenlet(类似于打patch).他和线程框架性能比高大概4倍(看下图,是gevent和paste的对比):

工作暂时没有用gevent的地方,这里就简单的对http://sdiehl.github.com/gevent-tutorial的一些例子和内容翻译:

1 同步和异步

import gevent
def foo():
print('Running in foo')
gevent.sleep(0) #让当前的greenlet睡眠N秒,这0标识控制其它协程而不会让其它进程睡眠
print('Explicit context switch to foo again') def bar():
print('Explicit context to bar')
gevent.sleep(0)
print('Implicit context switch back to bar') gevent.joinall([ #gevent.Greenlet实例,直到这个greenlet完成或者超时
gevent.spawn(foo), #spawn可以实现一个grennlet实例并且加到队列并且启动,效果类似于gevent.Greenlet(foo).start()
gevent.spawn(bar),
])

执行结果的效果图:

dongwm@localhost ~ $ python test.py
Explicit context to bar
Running in foo
Explicit context switch to foo again
Implicit context switch back to bar

import time

import gevent
from gevent import select #类似于内置的select.select()实现(请关注http://www.dongwm.com/archives/guanyuselectyanjiu/),只是将线程操作改成了greenlet start = time.time()
tic = lambda: 'at %1.1f seconds' % (time.time() - start) def gr1():
print('Started Polling: ', tic())
select.select([], [], [], 2) #参数分别是,等待的可读列表,等待的可写列表,等待的可执行列表,超时时间(这里是2秒)
print('Ended Polling: ', tic()) def gr2():
print('Started Polling: ', tic())
select.select([], [], [], 2)
print('Ended Polling: ', tic()) def gr3():
print("Hey lets do some stuff while the greenlets poll, at", tic())
gevent.sleep(1) gevent.joinall([
gevent.spawn(gr1),
gevent.spawn(gr2),
gevent.spawn(gr3),
])

执行结果:

dongwm@localhost ~ $ python test.py
(‘Hey lets do some stuff while the greenlets poll, at’, ‘at 0.0 seconds’) #因为gr1和gr2开始是阻塞的,gr3直接打印
(‘Started Polling: ‘, ‘at 0.0 seconds’)
(‘Started Polling: ‘, ‘at 0.0 seconds’)
(‘Ended Polling: ‘, ‘at 2.0 seconds’)
(‘Ended Polling: ‘, ‘at 2.0 seconds’)

import gevent
import random def task(pid):
gevent.sleep(random.randint(0,2)*0.001)
print('Task', pid, 'done') def synchronous(): #同步
for i in range(1,10):
task(i) def asynchronous(): #异步
threads = [gevent.spawn(task, i) for i in xrange(10)]
gevent.joinall(threads) print('Synchronous:')
synchronous() print('Asynchronous:')
asynchronous()

执行结果:

dongwm@localhost ~ $ python test.py
Synchronous: #协程不会控制其它进程睡眠,所以挨个执行
(‘Task’, 1, ‘done’)
(‘Task’, 2, ‘done’)
(‘Task’, 3, ‘done’)
(‘Task’, 4, ‘done’)
(‘Task’, 5, ‘done’)
(‘Task’, 6, ‘done’)
(‘Task’, 7, ‘done’)
(‘Task’, 8, ‘done’)
(‘Task’, 9, ‘done’)
Asynchronous: #他们放在grennlet里面,sleep的时间是随机的,完成顺序也就不同了
(‘Task’, 2, ‘done’)
(‘Task’, 3, ‘done’)
(‘Task’, 5, ‘done’)
(‘Task’, 7, ‘done’)
(‘Task’, 9, ‘done’)
(‘Task’, 6, ‘done’)
(‘Task’, 1, ‘done’)
(‘Task’, 0, ‘done’)
(‘Task’, 8, ‘done’)
(‘Task’, 4, ‘done’)

 
import gevent
from gevent import Greenlet def foo(message, n):
gevent.sleep(n)
print(message) thread1 = Greenlet.spawn(foo, "Hello", 1) #实例化Greenlet
thread2 = gevent.spawn(foo, "I live!", 2) #实例化gevent,其实也是创建Greenlet实例,只是包装了一下
thread3 = gevent.spawn(lambda x: (x+1), 2) #一个lambda表达式 threads = [thread1, thread2, thread3]
gevent.joinall(threads) #等待所有greenlet完成

执行结果:

dongwm@localhost ~ $ python test.py
Hello
I live! #打印出来效果不明显,事实上等待一秒打印第一行,再等待一秒打印第二行,然后马上完成(lambda没有显示)

import gevent
from gevent import Greenlet class MyGreenlet(Greenlet): #重载Greenlet类 def __init__(self, message, n):
Greenlet.__init__(self)
self.message = message
self.n = n def _run(self): #重写_run方法
print(self.message)
gevent.sleep(self.n) g = MyGreenlet("Hi there!", 3)
g.start()
g.join()

import gevent

def win():
return 'You win!' def fail():
raise Exception('You fail at failing.') winner = gevent.spawn(win)
loser = gevent.spawn(fail) print(winner.started) # started表示的Greenlet是否已经开始,返回布尔值
print(loser.started) # True try:
gevent.joinall([winner, loser])
except Exception as e:
print('This will never be reached') print(winner.value) # value表示greenlet实例返回值:'You win!'
print(loser.value) # None print(winner.ready()) # 是否已停止Greenlet的布尔值,True
print(loser.ready()) # True print(winner.successful()) # 表示的Greenlet是否已成功停止,而不是抛出异常,True
print(loser.successful()) # False
print(loser.exception) #打印异常的报错信息

执行结果:

dongwm@localhost ~ $ python test.py
True
True
Traceback (most recent call last):
File “/usr/lib/python2.7/site-packages/gevent-1.0dev-py2.7-linux-i686.egg/gevent/greenlet.py”, line 328, in run
result = self._run(*self.args, **self.kwargs)
File “test.py”, line 7, in fail
raise Exception(‘You fail at failing.’)
Exception: You fail at failing.
<Greenlet at 0xb73cd39cL: fail> failed with Exception

You win!
None
True
True
True
False
You fail at failing.

import gevent
from gevent import Timeout seconds = 10 timeout = Timeout(seconds)
timeout.start() def wait():
gevent.sleep(10) try:
gevent.spawn(wait).join()
except Timeout:
print 'Could not complete'

上面的例子是可以执行完成的,但是假如修改seconds = 5,让数值少入sleep,那么就会有超时被捕捉到

还可以使用with关键字处理上下文:

import gevent
from gevent import Timeout time_to_wait = 5 # seconds class TooLong(Exception):
pass with Timeout(time_to_wait, TooLong):
gevent.sleep(10)

以及其他的方式的:

 
import gevent
from gevent import Timeout def wait():
gevent.sleep(2) timer = Timeout(1).start()
thread1 = gevent.spawn(wait) #这种超时类型前面讲过 try:
thread1.join(timeout=timer)
except Timeout:
print('Thread 1 timed out') timer = Timeout.start_new(1) #start_new是一个快捷方式
thread2 = gevent.spawn(wait) try:
thread2.get(timeout=timer) #get返回greenlet的结果,包含异常
except Timeout:
print('Thread 2 timed out') try:
gevent.with_timeout(1, wait) #如果超时前返回异常,取消这个方法
except Timeout:
print('Thread 3 timed out')

2 数据结构

import gevent
from gevent.event import AsyncResult a = AsyncResult() #保存一个值或者一个异常的事件实例 def setter():
gevent.sleep(3) #3秒后唤起所有线程的a的值
a.set() #保存值,唤起等待线程 def waiter():
a.get() # 3秒后get方法不再阻塞,返回存贮的值或者异常
print 'I live!' gevent.joinall([
gevent.spawn(setter),
gevent.spawn(waiter),
])

更清晰的例子:

import gevent
from gevent.event import AsyncResult
a = AsyncResult() def setter():
gevent.sleep(3)
a.set('Hello!') def waiter():
print a.get() gevent.joinall([
gevent.spawn(setter),
gevent.spawn(waiter),
])
import gevent
from gevent.queue import Queue #类似于内置的Queue tasks = Queue() #队列实例 def worker(n):
while not tasks.empty():
task = tasks.get()
print('Worker %s got task %s' % (n, task))
gevent.sleep(0) print('Quitting time!') def boss():
for i in xrange(1,25):
tasks.put_nowait(i) #非阻塞的把数据放到队列里面 gevent.spawn(boss).join() gevent.joinall([
gevent.spawn(worker, 'steve'),
gevent.spawn(worker, 'john'),
gevent.spawn(worker, 'nancy'),
])

执行结果:

[root@248_STAT ~]# python !$
python test.py
Worker steve got task 1 #3个用户循环的取出数据
Worker john got task 2
Worker nancy got task 3
Worker steve got task 4
Worker nancy got task 5
Worker john got task 6
Worker steve got task 7
Worker john got task 8
Worker nancy got task 9
Worker steve got task 10
Worker nancy got task 11
Worker john got task 12
Worker steve got task 13
Worker john got task 14
Worker nancy got task 15
Worker steve got task 16
Worker nancy got task 17
Worker john got task 18
Worker steve got task 19
Worker john got task 20
Worker nancy got task 21
Worker steve got task 22
Worker nancy got task 23
Worker john got task 24
Quitting time!
Quitting time!
Quitting time!

一个更复杂的例子:

import gevent
from gevent.queue import Queue, Empty tasks = Queue(maxsize=3) #限制队列的长度 def worker(n):
try:
while True:
task = tasks.get(timeout=1) # 减少队列,超时为1秒
print('Worker %s got task %s' % (n, task))
gevent.sleep(0)
except Empty:
print('Quitting time!') def boss():
"""
Boss will wait to hand out work until a individual worker is
free since the maxsize of the task queue is 3.
""" for i in xrange(1,10):
tasks.put(i) #这里boss没有盲目的不停放入数据,而是在当最大三个队列数有空余才放入数据,事实上方法转换过程中,boss放入三个数据,worker取出三个数据,boss再放入数据....
print('Assigned all work in iteration 1') for i in xrange(10,20):
tasks.put(i)
print('Assigned all work in iteration 2') gevent.joinall([
gevent.spawn(boss),
gevent.spawn(worker, 'steve'),
gevent.spawn(worker, 'john'),
gevent.spawn(worker, 'bob'),
])

import gevent

from gevent.pool import Group
def talk(msg):
for i in xrange(3):
print(msg) g1 = gevent.spawn(talk, 'bar')
g2 = gevent.spawn(talk, 'foo')
g3 = gevent.spawn(talk, 'fizz') group = Group() #保持greenlet实例的组运行,连接到没个项目,在其完成后删除
group.add(g1)
group.add(g2)
group.join() group.add(g3)
group.join()

看更加明确的例子:

import gevent
from gevent import getcurrent
from gevent.pool import Group group = Group() def hello_from(n):
print('Size of group', len(group))
print('Hello from Greenlet %s' % id(getcurrent())) #获取当前gevent实例的id group.map(hello_from, xrange(3)) #map迭代方法,参数为方法和其参数 def intensive(n):
gevent.sleep(3 - n)
return 'task', n print('Ordered') ogroup = Group()
for i in ogroup.imap(intensive, xrange(3)): #相当于 itertools.imap,返回一个迭代器, 它是调用了一个其值在输入迭代器上的函数, 返回结果. 它类似于函数 map() , 只是前者在
#任意输入迭代器结束后就停止(而不是插入None值来补全所有的输入)
print(i) print('Unordered') igroup = Group()
for i in igroup.imap_unordered(intensive, xrange(3)):
print(i)

执行结果:

[root@248_STAT ~]# python test.py
(‘Size of group’, 3)
Hello from Greenlet 314818960
(‘Size of group’, 3)
Hello from Greenlet 314819280
(‘Size of group’, 3)
Hello from Greenlet 314819440
Ordered
(‘task’, 0)
(‘task’, 1)
(‘task’, 2)
Unordered
(‘task’, 2)
(‘task’, 1)
(‘task’, 0)

还能限制pool池的大小

import gevent
from gevent import getcurrent
from gevent.pool import Pool pool = Pool(2) def hello_from(n):
print('Size of pool', len(pool)) pool.map(hello_from, xrange(3))

返回结果:

[root@248_STAT ~]# python test.py
(‘Size of pool’, 2)
(‘Size of pool’, 2)
(‘Size of pool’, 1) #因为上面的pool容纳不了第三个,这是一个新的pool

以下是作者写的一个pool操作类:

from gevent.pool import Pool

class SocketPool(object):

    def __init__(self):
self.pool = Pool(1000) #设置池容量1000
self.pool.start() def listen(self, socket):
while True:
socket.recv() def add_handler(self, socket):
if self.pool.full(): #容量慢报错
raise Exception("At maximum pool size")
else: #否则执行在新的grenlet里面执行listen方法
self.pool.spawn(self.listen, socket) def shutdown(self):
self.pool.kill() #关闭pool

from gevent import sleep
from gevent.pool import Pool
from gevent.coros import BoundedSemaphore sem = BoundedSemaphore(2) #设定对共享资源的访问数量 def worker1(n):
sem.acquire() #获取资源
print('Worker %i acquired semaphore' % n)
sleep(0)
sem.release() #释放资源
print('Worker %i released semaphore' % n) def worker2(n):
with sem: #使用with关键字
print('Worker %i acquired semaphore' % n)
sleep(0)
print('Worker %i released semaphore' % n) pool = Pool()
pool.map(worker1, xrange(0,2))
pool.map(worker2, xrange(3,6))

执行结果:

[root@248_STAT ~]# python test.py
Worker 0 acquired semaphore
Worker 1 acquired semaphore #因为pool能容纳这2个请求,所以同时获取,再释放
Worker 0 released semaphore
Worker 1 released semaphore
Worker 3 acquired semaphore #因为只能接收2个,那么5就要到下一轮
Worker 4 acquired semaphore
Worker 3 released semaphore
Worker 4 released semaphore
Worker 5 acquired semaphore
Worker 5 released semaphore

一个gevent教材上面说过的ping pong的那个协程例子的另一个实现:

import gevent

from gevent.queue import Queue
from gevent import Greenlet class Actor(gevent.Greenlet): #自定义actor类 def __init__(self):
self.inbox = Queue() #收件箱作为一个队列
Greenlet.__init__(self) def receive(self, message):
raise NotImplemented() #内置常量,表面意为没有实施 def _run(self): #
self.running = True while self.running:
message = self.inbox.get() #获取队列数据
self.receive(message) class Pinger(Actor):
def receive(self, message): #重写方法
print message
pong.inbox.put('ping') #当获取收件箱有数据,获取数据,再放入数据(注意:是ping中放pong数据),其中pong是一个局部变量,它是Ponger的实例,以下的同理
gevent.sleep(0) class Ponger(Actor):
def receive(self, message):
print message
ping.inbox.put('pong')
gevent.sleep(0) ping = Pinger()
pong = Ponger() ping.start()
pong.start() ping.inbox.put('start') #最开始都是阻塞的,给一个触发
gevent.joinall([ping, pong])

from:http://www.dongwm.com/archives/guanyugeventdeyixielijieyi-2/

英文原版:http://sdiehl.github.io/gevent-tutorial/

关于gevent的一些理解(一)的更多相关文章

  1. 关于gevent的一些理解(二)

    3 实际应用 1 zeromq和gevent: zeromq的介绍请参看:http://www.infoq.com/cn/news/2010/09/introduction-zero-mq 假设你已经 ...

  2. 转:[gevent源码分析] 深度分析gevent运行流程

    [gevent源码分析] 深度分析gevent运行流程 http://blog.csdn.net/yueguanghaidao/article/details/24281751 一直对gevent运行 ...

  3. [gevent源代码分析] 深度分析gevent执行流程

    一直对gevent执行流程比較模糊,近期看源代码略有所得.不敢独享.故分享之. gevent是一个高性能网络库,底层是libevent,1.0版本号之后是libev.核心是greenlet.geven ...

  4. gevent简介

    gevent是基于协程的Python网络库. 协程存在的意义:对于多线程应用,CPU通过切片的方式来切换线程间的执行,线程切换时需要耗时(保存状态,下次继续).协程,则只使用一个线程,在一个线程中规定 ...

  5. 【译】深入理解python3.4中Asyncio库与Node.js的异步IO机制

    转载自http://xidui.github.io/2015/10/29/%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3python3-4-Asyncio%E5%BA%93% ...

  6. 练习PYTHON之GEVENT

    这个只是作了第一个样例,里面还有很多高级的技巧,希望以后用得着. 我觉得因为以前看过几本LINUX内核,关于异步非阻塞IO,信号,锁之类的,所以理解起来,还可以. import gevent def ...

  7. join函数——Gevent源码分析

    在使用gevent框架的时候,我们经常会使用join函数,如下: def test1(id): print(id) gevent.sleep(0) print(id, 'is done!') t = ...

  8. gevent调度流程解析

    gevent是目前应用非常广泛的网络库,高效的轮询IO库libev加上协程(coroutine),使得gevent的性能非常出色,尤其是在web应用中.本文介绍gevent的调度流程,主要包括geve ...

  9. Python并发编程协程(Coroutine)之Gevent

    Gevent官网文档地址:http://www.gevent.org/contents.html 基本概念 我们通常所说的协程Coroutine其实是corporate routine的缩写,直接翻译 ...

随机推荐

  1. Oracle 补丁体系 及 opatch 工具 介绍

    一. CPU(Critical Patch Update) 一个CPU内包含了对多个安全漏洞的修复,并且也包括相应必需的非安全漏洞的补丁.CPU是累积型的,只要安装最新发布的CPU即可,其中包括之前发 ...

  2. hadoop零基础入门之DKH安装准备

    前几天去参加了一个线下的聚会,参加聚会的基本都是从事互联网工作的.会上有人提到了区块链,从而引发了一场关于大数据方面的探讨.我也是从去年才正式接触大数据,一直在学习hadoop.相信接触过hadoop ...

  3. 既做无线客户端又做无线ap、又可只存在一种模式

    1. 1.1 打开 /barrier_breaker/package/base-files/files/etc/init.d 加入 disable_sta_mode_wifi_interfaces # ...

  4. 重置SQL Server sa密码

    查询分析器,连接时,身份验证使用"使用windows身份验证" 然后,执行: EXEC sp_password NULL, '新密码', 'Sa'

  5. android开发常用组件【持续更新中。。。】

    UI相关 图片 Android-Universal-Image-Loader:com.nostra13.universalimageloader:异步加载.缓存.显示图片 ImageLoader:co ...

  6. 【C#】datetimepicker里面如何设置日期为当天日期,而时间设为0:00或23:59?

    今天无意中发现要根据日期查询时间,datatimepicker控件会把时间默认成当前时间(当你的控件只显示日期时),这样查询出来的出来的数据会有误差,用来下面的办法成功设置日期为当天日期,而时间设为0 ...

  7. BEGIN-2_蓝桥杯_序列求和

    问题描述 求1+++...+n的值. 输入格式 输入包括一个整数n. 输出格式 输出一行,包括一个整数,表示1+++...+n的值. 样例输入 样例输出 样例输入 说明:有一些试题会给出多组样例输入输 ...

  8. bzoj3157 3516 国王奇遇记

    Description Input 共一行包括两个正整数N和M. Output 共一行为所求表达式的值对10^9+7取模的值. 特判m=1 m≠1时: 设S[u]=sigma(i^u*m^i) m*S ...

  9. post 中文数据到elasticsearch restful接口报json_parse_exception 问题

    我们的客户端程序直接调用es 的restful接口, 通过post json数据去查询, 但post数据有中文的时候,有些中文会报异常,有些中文不会 {"error":{" ...

  10. EC20模块(mdm9607)复用pin脚当作普通gpio的设置方法

    修改pin37~40,当作普通gpio的方法如下: 下面代码截图需要确认是否一样,如不一样请修改: 修改pin41~42 ,当作普通gpio方法如下: Pin24~27,当作普通gpio方法如下: P ...