Eventlet(http://eventlet.net/)是一个python的网络库,他可以通过协程的方式来实现并发。Eventlet协程又称GreenThread(绿色线程),所谓的并发,就是创建多个GreenThread,并对其进行管理,以实现非阻塞式的I/O。比如说用eventlet可以很方便的写一个性能很好的web服务器,或者是一个效率很高的网页爬虫,这都归功于eventlet的“绿色线程”,以及对“绿色线程”的管理机制。更让人不可思议的是,eventlet为了实现“绿色线程”,竟然对python的和网络相关的几个标准库函数进行了改写,并且可以以补丁(patch)的方式导入到程序中,因为python的库函数只支持普通的线程,而不支持协程,eventlet称之为“绿化”。Openstack中的大部分项目都采用所谓的协程(coroutine)模型。
1.什么是协程
协程与线程差不多,也就是一条执行序列,拥有自己独立的栈,局部变量和指令指针,同时又与其它协同程序共享全局变量和其它大部分东西。线程与协同程序的主要区别在于,一个具有多线程的程序可以同时运行几个线程,而协同程序却需要彼此协作地运行。就是说,一个具有多个协同程序的程序在任何时刻只能运行一个协同程序,并且正在运行的协同程序只会在其显示地挂起时,它的执行才会暂停.
2.协程优点
- 每个coroutine有自己私有的stack及局部变量
- 同一时间只有一个coroutine在执行,无需对全局变量加锁
- 顺序可控,完全由程序控制执行的顺序。而通常的多线程一旦启动,它的运行时序是没法预测的,因此通常会给测试所有的情况带来困难。所以能用coroutine解决的场合应当优先使用coroutine。
3.几个主要API的理解
3.1 Greenthread Spawn(spawn,孵化的意思,即如何产生greenthread)
主要有3个函数可以创建绿色线程:
* 3.1.1 spawn(func, *args, **kwargs):创建一个绿色线程去运行func这个函数,后面的参数是传递给这个函数的参数。返回值是一个eventlet.GreenThread对象,这个对象可以用来接受func函数运行的返回值。在绿色线程池还没有满的情况下,这个绿色线程一被创建就立刻被执行。其实,用这种方法去创建线程也是可以理解的,线程被创建出来,肯定是有一定的任务要去执行,这里直接把函数当作参数传递进去,去执行一定的任务,就好像标准库中的线程用run()方法去执行任务一样。
* 3.1.2 spawn_n(func, *args, **kwargs):这个函数和spawn()类似,不同的就是它没有返回值,因而更加高效,这种特性,使它也有存在的价值。
* 3.1.3 spawn_after(seconds, func, *args, **kwargs):这个函数和spawn()基本上一样,都有一样的返回值,不同的是它可以限定在什么时候执行这个绿色线程,即在seconds秒之后,启动这个绿色线程。
3.2 Greenthread Control
- 3.2.1 sleep(seconds=0):中止当前的绿色线程,以允许其它的绿色线程执行。
- 3.2.2 eventlet.GreenPool:这是一个类,在这个类中用set集合来容纳所创建的绿色线程,并且可以指定容纳线程的最大数量(默认是1000个),它的内部是用Semaphore和Event这两个类来对池进行控制的,这样就构成了线程池。
其中,有几个比较重要的方法: - running(self):返回当前池中的绿色线程数
- free():返回当前池中仍可容纳的绿色线程数
- spawn()、spawn_n():创建新的绿色线程
starmap(self, function, iterable)和imap(self, function, *iterables):这两个函数和标准的库函数中的这两个函数实现的功能是一样的,所不同的是这里将这两个函数的执行放到了绿色线程中。前者实现的是从iterable中取出每一项作为function的参数来执行,后者则是分别从iterables中各取一项,作为function的参数去执行。如:imap(pow, (2,3,10), (5,2,3)) –> 32 9 1000,starmap(pow, [(2,5), (3,2), (10,3)]) –> 32 9 1000
3.2.3 eventlet.GreenPile
这也是一个类,而且是一个很有用的类,在它内部维护了一个GreenPool对象和一个Queue对象。具体参加官方API&docs3.2.4 eventlet.Queue
参见官方文档
3.3 Patching Functions(补丁方法)
这里就是之前所说的“绿化”,经过eventlet“绿化”过的模块都在eventlet.green中,导入他们主要有两种方法:
* 3.3.1 from eventlet.green import … + import_patched(module_name,*additional_modules,**kw_additional_modules),如:
from eventlet.green import socket
from eventlet.green import SocketServer
BaseHTTPServer = eventlet.import_patched('BaseHTTPServer',
('socket', socket),
('SocketServer', SocketServer))
BaseHTTPServer = eventlet.import_patched('BaseHTTPServer',
socket=socket, SocketServer=SocketServer)
这种方法有个缺陷就是不支持“延迟绑定”(late binding),比如在运行时导入模块。
* 3.3.2 monkey_patch(all=True,os=None, select=None, socket=None,thread=None,time=None,psycopg=None),如:
import eventlet
eventlet.monkey_patch(socket=True, select=True)
参考
http://blog.csdn.net/hackerain/article/details/7836993