gevent基于协程的网络库,基于libev的快速的事件循环,基于greenlet的轻量级执行单元,重用了Python标准库中的概念,支持socket、ssl、三方库通过打猴子补丁的形式来提供同步方式编写代码的异步支持,dns解析通过线程池或c-ares,内置的tcp udp http服务器,支持多进程,线程池。
gevent和eventlet
2009年当时eventlet不支持livevent
当时eventlet的monkey-patch有bug导致socket操作会挂起
its Hub API is geared towards pure Python event loops. Making it work smoothly would require significant changes in the interface and implementation of every other hub. The socket module bugs were also specific to event loop, so even though I fixed them for pyevent, they were still present in every other hub.
gevent在libevent的基础上
当然最新的实现是使用了libev
libevent是事件循环,使用epoll、kqueue,dns是异步的,同时它提供了http服务器。而eventlet则是维持的纯python的事件循环(最近才支持epoll)。
除了效率,还集成了信号处理,其他使用libevent的库也可以集成进来,dns解析也可以异步了,wsgi服务器也是在libevent的自带服务器上运行的(很快)
和python标准的风格相同
例如线程的事件等都一样
不同点
没有eventlet.db_pool
没有多进程eventlet.processes
如果是在twister的reactor上使用
事件循环
gevent告诉操作系统等数据到达的时候来通知它,然后gevent就可以继续处理其他的协程,例如已经获得了数据的。
不像其他的网络库,gevent在一个协程中隐式启动循环,不用调用run或者dispatch什么的,当它要阻塞的时候,就会获取hub实例并切换到其中,也就是把控制权交给了hub,如果此时还没有hub就会自动创建一个。
切换规则
注意只有一个greenlet放弃了控制才能执行其他的(调用阻塞函数会切换回hub),这对于io频繁的系统当然没问题,但是对于cpu频繁的系统、或者是调用一些能绕过libev的函数。
锁、信号量什么的其实没什么用了,而event、asyncresult、queue等则还是有用的。
使用
创建一个Greenlet然后调用它的start函数,或者直接调用spawn函数。然后在当前协程放弃控制后会切换到并执行。如果greenlet执行时触发了异常,并不会超出greenlet的界限,只是打印stacktrace 默认是到stderror。
join等待该greenlet退出,kill中断该greenlet执行,get获得返回的值或re raise它产生的异常。
可以派生Greenlet,更改它的str方法来改变显示的traceback信息,但是得在初始化函数中先调用Greenlet.init(self)。
class MyNoopGreenlet(Greenlet):
def __init__(self, seconds):
Greenlet.__init__(self)
self.seconds = seconds
def _run(self):
gevent.sleep(self.seconds)
def __str__(self):
return 'MyNoopGreenlet(%s)' % self.seconds
kill可附带一个自定义的异常,但是可能该协程会捕获这个异常,可以附带timeout参数,也可以直接指定block=False来异步执行。