gevent文档翻译-介绍
转载:http://www.darkbull.net/article/gevent_doc--introduction/
翻译题记:gevent是个小巧的,性能又很nb的网络库,短短几行代码,能承受成千上万连接的服务器就出来了。simple is best,简单流水账一般地翻译下gevent官方文档作为自己的学习笔记,以便日后快速回忆,也权当帮助文档让对gevent感兴趣的朋友作为入门文 档。 ---- 装逼题记到此结束 ----
原文地址:http://www.gevent.org/contents.html
介绍
gevent的主要功能是作为网络库(不用再去纠结epoll, kqueue的细节),短短几行代码就能写出性能非常高效的网络服务器。它基于libevent,使用greenlet作为并行库,向目标代码提供同步的 接口(意思就是说,代码可以写的像同步阻塞socket,却可以享受远高于阻塞socket的网络io性能)
主要特性:
- 高效的事件循环机制(基于linux epoll,freebsd kqueue)
- 基于greenlet的轻量级执行单元(协程、微线程,随便你怎么叫,反正就是与原生os thread不一样的但又有点类似的东东,调用开销远比os thread小,谁叫Python单进程无法享受多核的威力呢~~)
- 重用python标准库接口完全一致(如: Event, Queue)
- 支持socket ssl(Cooperative socket and ssl modules)
- 可以使用gevent.monkey替换部分标准库,让阻塞socket代码无需修改就享受gevent的高效特性
- 基于libevent-dns的DNS查询
- 基于libevent-http的高效的WSGI服务器
安装
linux下安装直接使用easy_install或者pip: pip install greenlet pip install gevent
windows下也可以使用easy_install或者pip,如果安装失败,到这里下载相应的exe
python2.6+默认支持ssl,所以2.6之前的python版本还需要安装ssl模块(如果需要用到ssl的话)
例子
>>> import gevent
>>> from gevent import socket
>>> urls = ['www.google.com', 'www.example.com', 'www.python.org']
>>> jobs = [gevent.spawn(socket.gethostbyname, url) for url in urls]
>>> gevent.joinall(jobs, timeout=2)
>>> [job.value for job in jobs]
['74.125.79.106', '208.77.188.166', '82.94.164.162']
例子中创建了三个任务“并行”的执行,joinall将等待这三个任务结束后才返回,结果保存在gevent.Greenlet.value中,gevent.socket.gethostbyname用于获取域名的ip,与标准库socket.gethostbyname功能一样,只是这里的接口不会阻塞,而允许greenlet去调度。
Monkey patching
上个例子使用gevent.socket ,如果使用标准库的socket模块,将花费大约原来三倍的时间,因为标准socket模块会阻塞python解释器直到有结果返回,当然这样就无法充分 利用cpu,所以使用gevent.socket来代替标准socket模块,应该是个不错的注意~~~~
gevent提供了非常方便的接口用于在程序中替换标准模块,可以让gevent多协和环境,几条语句即可:
- from gevent import monkey
- monkey.patch_socket()
- import urllib2 # it's usable from multiple greenlets now
事件循环
与其他网络库一样,gevent也有自己的事件循环机制,只是gevent的事件循环机制不需要显式的在代码中启动,因此没有类似 reactor.run() 这样的代码。gevent事件调度实现,主要与Hub对象有关,具体感兴趣的同学可以阅读gevent源码,这个Hub机制笔者也不是很明白,有空研究一 下。
gevent默认使用系统最高效的polling机制,linux上是epoll,mac或者freebsd是kqueue,也可以设计环境变量来使用其他的机制(ms默认的就是最好的)
gevent.core模块主要是对libevent api的封装,只是在这里只能使用异步的api
并行相关
其实所有的greenlet协程都在一个os线程里运行与调度,因此对于io密集性的应用没有任何问题,但对于cpu密集性的应用就。。。
在不同的greenlet协程间访问同一对象,通常情况下不需要Lock或者Semaphore,但是其他的一些与多线程有关的抽象东东还是有用的,像Event, Queue等等下:
- Event:
- AsyncResult:
- Queue:
轻量级线程
spwan()方法创建一个Greenlet协程,并调用其start方法。start方法将
如果协程在运行过程中抛出了未被处理的异常,该协程将退出运行,并将错误的信息打印出来(默认行为:错误信息被异步打印到sys.stderr):
>>> gevent.spawn(lambda : 1/0)
>>> gevent.sleep(1)
Traceback (most recent call last):
...
ZeroDivisionError: integer division or modulo by zero
<Greenlet at 0x7f2ec3a4e490: <function <lambda...>> failed with ZeroDivisionError
Greenlet实例的一些常用方法:
- join - 等待直到greenlet退出
- kill - 强制结束greenlet协程
- get - 如果协程正常结束,获取greenlet协程的运行结果;如果协程被强制结束或者在运行过程中抛出未捕获异常,重新招聘异常
我们也可以继承Greenlet,通过重写__str__方法自定义输出。通常情况下子类在 _run方法中实现协程的逻辑,例如:
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一个正在运行的greenlet协程,kill过程将“唤醒”原本sleeping的greenlet,并让其抛出一个GreenletExit异常,结束该协程
>>> g = MyNoopGreenlet(4)
>>> g.start()
>>> g.kill()
>>> g.dead
True
kill默认抛出的GreenletExit异常,通常不会打出traceback信息,但如果向kill方法传递其他异常对象,该异常将会被重新抛出:
>>> g = MyNoopGreenlet.spawn(5) # spawn() creates a Greenlet and starts it
>>> g.kill(Exception("A time to kill"))
Traceback (most recent call last):
...
Exception: A time to kill
MyNoopGreenlet(5) failed with Exception
kill方法有一个timeout关键字参数,用于设置超时时间(单位是秒),如果greenlet协程在指定时间内没有结束,将被强制退出
超时
gevent许多函数都是同步的,阻塞当前协程直到操作结束,例如对协程调用kill方法,将一直阻塞直到该协程退出时。这些函数可以通过传递参数 block=False,被设置为非阻塞的。另外,许多这些同步函数支持timeout参数,设置阻塞的超时时间。(例如:Event.wait(), Greenlet.Join(), Greenlet.kill, AsyncResult.get(), ...) socket和SSLObject对象可以通过settimeout方法设置timeout。gevent还提供一个Timeout类,用于设置协程的 timeout
更多阅读
通过Pool类控制同时运行的协程数(例子:example: dns_mass_resolve.py)
gevent包含 TCP/SSL/HTTP/WSGI servers. See Implementing servers.