待更新
介绍
gevent是基于协程的Python网络库。特点:
基于libev的快速事件循环(Linux上epoll,FreeBSD上kqueue)。
基于greenlet的轻量级执行单元。
API的概念和Python标准库一致(如事件,队列)。
可以配合socket,ssl模块使用。
能够使用标准库和第三方模块创建标准的阻塞套接字(gevent.monkey)。
默认通过线程池进行DNS查询,也可通过c-are(通过GEVENT_RESOLVER=ares环境变量开启)。
TCP/UDP/HTTP服务器
子进程支持(通过gevent.subprocess)
线程池
安装
gevent目前支持python2.5-2.7,python2.6以前的版本如果要使用ssl还需要安装ssl模块。
# pip install gevent
实例
下面的示例展示了如何同时运行任务。
>>> 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.128.106', '93.184.216.119', '82.94.164.162']
job发起之后,gevent.joinall()等待完成,不超过2秒。结果收集在gevent.Greenlet.value属性。gevent.socket.gethostbyname()和socket.gethostbyname()的接口一样,但它并不阻塞解释器,其他greenlet继续畅通无阻的处理请求。
灵猴补丁(Monkey patching)
上面例子使gevent.socket进行socket操作。如果使用标准socket模块将有3倍耗时,因为DNS请求是串行的。在greenlet中使用标准socket模块毫无意义,这些模块和包是怎么建立在socket之上的?
monkey patching这时起作用了,gevent.monkey小心地使用兼容副本替换标准socket模块的函数和类。这样,即使是不知道gevent的模块也受益于greenlet环境运行。
>>> from gevent import monkey; monkey.patch_socket()
>>> import urllib2 # it's usable from multiple greenlets now
下面是使用urllib2进行下载的实例:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Copyright (c) 2009 Denis Bilenko. See LICENSE for details.
"""Spawn multiple workers and wait for them to complete"""
urls = ['http://www.google.com', 'http://www.yandex.ru', 'http://www.python.org']
import gevent
from gevent import monkey
# patches stdlib (including socket and ssl modules) to cooperate with other greenlets
monkey.patch_all()
import urllib2
def print_head(url):
print('Starting%s' % url)
data = urllib2.urlopen(url).read()
print('%s:%sbytes:%r' % (url, len(data), data[:50]))
jobs = [gevent.spawn(print_head, url) for url in urls]
gevent.wait(jobs)
执行结果:
# ./test.pyStarting http://www.google.com
Starting http://www.yandex.ru
Starting http://www.python.org
http://www.google.com: 11246 bytes: '
http://www.yandex.ru: 208804 bytes: '
Traceback (most recent call last):
...
Exception: A time to kill
MyNoopGreenlet(5) failed with Exception
kill还可以接受timeout参数指定greenlet退的等待秒数。注意,kill不能保证目标greenlet不会忽视该异常,因此给kill传递timeout是个好方法。
超时
gevent的API中的许多函数是同步的,阻塞当前greenlet直到操作完成。例如,kill会等到greenlet结束。多数可以传递参数block=False异步执行。
此外,许多同步函数接受超时参数,指定可以阻塞多久(比如:Event.wait(), Greenlet.join(), Greenlet.kill(),AsyncResult?.get()等)。
socket和SSLObject实例也可以超时,由setTimeout方法设置。
如果这些还不够用,Timeout类可以给任意(yielding)代码块增加超时。
了解更多
限制并发可以使用Pool类(参见实例: dns_mass_resolve.py)
外部资源
本文地址