今天听easystack一哥们讲nova协同并发,结合自己之前的认识。回顾一下openstack eventlet。
OpenStack作为热门的开源云平台,本身代码当然得支持高并发。
首先讲讲python的并发,python中的并发有:进程、线程、协程(Coroutines)。
进程和线程大家都比较清楚了,那什么是协程,协程介绍如下:
- 协程和线程比较像,每个协程都有⾃己的私有stack和局部变量
- 一个线程内可以有很多个协程
- 多个线程可以同时运行。但在一个线程内,同一时间只有一个协程在运行,无须对某些共享变量加锁
- 协程之间的执行顺序,完全由程序来控制
- 除非自己放弃执行,否则一直执行到结束
- 协程是一种概念,非操作系统可见,在多种语言中实现,如go、ruby等。eventlet是Python中实现之一
进程、线程、协程之间的关系可以用下图表示:
eventlet是对greenlet的封装,先了解下greenlet,下面是一个官方给出的例子:
1 from greenlet import greenlet
2
3 def test1():
4 print 12
5 gr2.switch()
6 print 34
7
8 def test2():
9 print 56
10 gr1.switch()
11 print 78
12
13 gr1 = greenlet(test1)
14 gr2 = greenlet(test2)
15 gr1.switch()
执行结果是:
12
56
34
程序很简单,定义两个协程,最后一行g1.switch()跳转到 test1() ,它打印12,然后跳转到 test2() ,打印56,然后跳转回 test1() ,打印34,然后 test1() 就结束,gr1死掉,回到父greenlet,不会再切换到test2,所以不会打印78。在上面的例子中main greenlet就是它们的父greenlet。
greenlet使用虽然简单,但是需要程序员显式的写代码在不同的协程之间切换,对于OpenStack这样的大项目显然是不现实的。
于是eventlet封装了greenlet,以下是eventlet的介绍:
- 由second life开源的高性能网络库
- 基于greenlet
- 通过patch标准模块实现协程
- 对greenlet封装,提供GreenThread
- 内部使用timer实现greenlet调度器
- 内部main loop 循环通过最小堆查找应该执行的greenlet
python 2.x 原生是不支持协程的,eventlet通过对标准库打patch实现协程,例如在Nova项目中 nova/cmd/__init__.py
import eventlet
from nova import debugger
if debugger.enabled():
# turn off thread patching to enable the remote debugger
eventlet.monkey_patch(os=False, thread=False)
else:
eventlet.monkey_patch(os=False)
其中eventlet.monkey_patch()就是对标准库打patch。
在调试Nova代码时,有时会因为协程导致调试不方便,可以把else语句里面的eventlet.monkey_patch(os=False)改为eventlet.monkey_patch(os=False, thread=False)
在eventlet的文档中有关于eventlet的使用,主要包含以下几个接口:
(1) spawn(func, *args, **kw)
启动一个greenthread来调用func函数,args和kw都是传递给func的参数。返回值是greenthread.GreenThread对象
(2) spawn_n(func, *args, **kw)
除了没有返回值,其他跟spawn一样
(3) spawn_after(seconds, func, *args, **kw)
在seconds秒之后启动
(4) sleep(seconds=0)
暂停当前greenthread,给其它greenthread执行的机会