greenlet,也就是协程,是Stackless的副产物,是一个更加原始的微线程的概念,但是没有调度(摘自http://www.oschina.net/p/greenlet/))。所以使用协程的话就需要自己处理调度问题。这样可以主动的在阻塞的时候可以让步给其他协程工作,提高CPU的利用率。

Python中主要通过greenlet模块来实现协程操作。greenlet.greenlet是greenlet type,一些基本操作:

  • greenlet(run=None, parent=None)

    创建一个greenlet对象(不执行),run指定执行回调,parent指定parent greenlet(就叫PG吧),默认PG是当前greenlet

  • greenlet.getcurrent()

    返回当前greenlet

  • greenlet.GreenletExit

    这个异常不会发送给PG,可以用来杀死一个greenlet


下面看一个例子greenlet_test.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from greenlet import greenlet

def test1():
print "test1 - start"
gr2.switch()
print "test1 - end"

def test2():
print " test2 - start"
gr1.switch()
print " test2 - end"

gr1 = greenlet(test1)
gr2 = greenlet(test2)
print gr1.parent
print gr2.parent
print greenlet.getcurrent()
gr1.switch()

看下执行结果:

1
2
3
4
5
6
7
#python greenlet_test.py
<greenlet.greenlet object at 0x7f622ec91eb0>
<greenlet.greenlet object at 0x7f622ec91eb0>
<greenlet.greenlet object at 0x7f622ec91eb0>
test1 - start
test2 - start
test1 - end

从结果看出,gr1和gr2有着相同的PG,也就是当前greenlet。

  • 首先gr1.switch()从当前greenlet切换到gr1执行,也就是test1(),所以首先输出test1 - start
  • test1中通过gr2.switch()切换到gr2,执行test2,输出test2 - start
  • 同上再次切换到gr1,执行test1,输出tset1 - end
  • 然后就结束了,为什么没有输出test2 - end呢?

协程之间的切换不是函数之间的调用,毕竟操作的是greenlet,比如从gr2切换到gr1,实际上是将gr1入栈直接执行(点击参考1,参考2,参考3),函数执行结束,gr1这个协程就结束了,它返回给的不是其他任何函数,而是返回给它的PG,而PG后面也没有任务了,整个程序退出,所以gr2后面没有机会再执行了,test2 - end就不会输出了。