example1:
#coding: utf-8
import greenlet
#coding: utf-8
import greenlet
def test(name):
print 'this is in the test: name=%s' % name
gr1 = greenlet.greenlet(run=test, parent=None)
gr1.switch('test')
gr1 = greenlet.greenlet(run=test, parent=None)
gr1.switch()
创建一个greenlet对象需要两个参数:
1、run 协程执行的入口函数,在example1中是test。
2、parent 此协程的父协程对象,如果为None,则为当前正在执行的协程。example1中父协程对象为
greenlet.getcurrent()返回的协程对象。当一个协程执行完毕之后,则会回到其parent协程执行,
如果parent协程已经执行完毕,则会回到parent的parent协程执行,以此类推。
协程的启动和切换依靠switch函数来实现。当调用switch启动一个协程时,switch中的参数是传递给
run的,这里的run其实质就是构造greenlet对象时run参数的值。example1中switch('test')中的
"test"传递给了test函数。当调用switch切换到一个已经启动过的协程时,传递给switch的参数将作
为被激活协程调用switch函数的返回值。直白的来说,就是被激活的那个switch的返回值就是激活时
那个switch所带的参数。看下面示例:
example2:
#coding: utf-8
import greenlet
def a_coroutine(name):
print 'this is in the a_coroutine : name=%s' % name
print 'switch to b_coroutine'
ret = b.switch('b_coroutine')
print 'back to a_coroutine ret=%s' % ret
def b_coroutine(name):
print 'this is in the b_coroutine : name=%s' % name
print 'switch to a_coroutine'
a.switch("I'm back")
print 'b_coroutine is over'
a = greenlet.greenlet(run=a_coroutine, parent=None)
b = greenlet.greenlet(run=b_coroutine, parent=None)
a.switch('a_coroutine')
程序输出为:
this is in the a_coroutine : name=a_coroutine
switch to b_coroutine
this is in the b_coroutine : name=b_coroutine
switch to a_coroutine
back to a_coroutine ret=I'm back
在b_coroutine函数中(其实也就是b协程),a.switch作为激活switch,在a_coroutine(a协程)函数中,b.switch
作为被激活的switch。所以b.switch的返回值就是a.switch所带的参数。
greenlet有个属性是parent,这个属性表示的是父协程,当当前的协程执行完之后,会回到parent协程执行。
这个属性可以在创建greenlet对象时指定parent参数来更改默认的parent协程。greenlet组成的协程结构
其实是个树形结构,当当前的协程执行完之后,会沿着parent走下去,直到到达根协程,根协程其实就是main程序。
注意这里能沿着parent协程执行下去的只能是当前协程,而非所有的协程。这个当前的协程其实可以是变的,只
要你调用switch切换到了其他协程,那么当前协程也会跟着变,这个parent可能也变了,协程的执行可能也变了。
example3:
#coding: utf-8
import greenlet
import StringIO
from greenlet import getcurrent
output = StringIO.StringIO()
def parent(sw_to, *args, **kwargs):
output.write(' --->%s' % getcurrent().name)
if sw_to is not None:
ret = sw_to.switch(*args, **kwargs)
output.write("----->%s ret=%s" % (getcurrent().name, str(ret)))
output.write('---->%s' % getcurrent().parent.name)
return None
def child(sw_to, *args, **kwargs):
output.write('----->%s' % getcurrent().name)
if sw_to is not None:
ret = sw_to.switch(*args, **kwargs)
output.write("---->%s ret=%s" % (getcurrent().name, str(ret)))
return None
def test1():
print '-------------test1-------------------'
getcurrent().name = 'root'
p1 = greenlet.greenlet(parent, parent=None)
p1.name = 'p1'
c1_1 = greenlet.greenlet(child, parent=p1)
c1_1.name = 'c1_1'
c1_2 = greenlet.greenlet(child, parent=p1)
c1_2.name = 'c1_2'
output.write('%s' % getcurrent().name)
#c1_1 协程开始执行,并且沿着树形结构,一直执行到root
c1_1.switch(None)
output.seek(0)
print output.read()
output.truncate(0)
output.write('%s' % getcurrent().name)
#c1_1已经执行完毕了,所以再次switch的时候,直接结束了.
c1_1.switch(c1_2, None)
output.seek(0)
print output.read()
output.truncate(0)
def test2():
print '-------------test2-------------------'
getcurrent().name = 'root'
p1 = greenlet.greenlet(parent, parent=None)
p1.name = 'p1'
c1_1 = greenlet.greenlet(child, parent=p1)
c1_1.name = 'c1_1'
c1_2 = greenlet.greenlet(child, parent=p1)
c1_2.name = 'c1_2'
output.write('%s' % getcurrent().name)
#c1_1切换到c1_2(c1_1的兄弟协程)之后,c1_2没有
#再切换回c1_1,协程也因此沿着parent执行,直到
#root,刚好形成一个闭环
c1_1.switch(c1_2, None)
output.seek(0)
print output.read()
output.truncate(0)
output.write('%s' % getcurrent().name)
#64行c1_1已经启动过了,只是在执行的过程中又切换到了
#c1_2中,这次再switch回去,则从上次switch挂起的地方
#恢复执行,然后依然沿着parent执行,因为c1_1和c1_2都
#拥有共同的parent p1,所以在64行的c1_1.switch时parent
#已经被执行过一遍了,此次的再次沿着parent执行,所以parent
#并没有输出任何东西,因为所有的parent都已经执行过了.
c1_1.switch(None)
output.seek(0)
print output.read()
output.truncate(0)
def test3():
print '-------------test3-------------------'
getcurrent().name = 'root'
p1 = greenlet.greenlet(parent, parent=None)
p1.name = 'p1'
c1_1 = greenlet.greenlet(child, parent=p1)
c1_1.name = 'c1_1'
c1_2 = greenlet.greenlet(child, parent=p1)
c1_2.name = 'c1_2'
output.write('%s' % getcurrent().name)
#c1_1启动之后切换到p1(c1_1的parent)然后p1
#再次切换回c1_1,c1_1没有再做切换操作,c1_1执行完毕之后
#回到parent协程继续执行,而p1刚好就是c1_1的parent,p1
#现在在switch处挂起,因此从switch处继续执行
#最终沿着parent执行到了root,最终形成了一个闭环,
#从哪开始,则又回到哪里继续执行
#root----->c1_1 --->p1---->c1_1 ret=None----->p1 ret=None---->root
c1_1.switch(p1, c1_1, None)
output.seek(0)
print output.read()
output.truncate(0)
def test4():
print '-------------test4-------------------'
getcurrent().name = 'root'
p1 = greenlet.greenlet(parent, parent=None)
p1.name = 'p1'
c1_1 = greenlet.greenlet(child, parent=p1)
c1_1.name = 'c1_1'
c1_2 = greenlet.greenlet(child, parent=p1)
c1_2.name = 'c1_2'
p2 = greenlet.greenlet(parent, parent=None)
p2.name = 'p2'
c2_1 = greenlet.greenlet(child, parent=p2)
c2_1.name = 'c2_1'
output.write('%s' % getcurrent().name)
#c1_1启动之后切换到了c2_1,这个c2_1和c1_1同一个root,但是其parent
#不再一样了,c1_1的parent是p1而c2_1的parent是p2,所以c_1切换到c2_1
#以后则沿着c2_1的parent执行了下去,c1_1切换出去以后,没有再显示的
#切换回来,所以c1_1以及其parent都没有被执行
#root----->c1_1----->c2_1 --->p2---->root
# -------- root<-
# | / \ |
# | / \ |
# | p1 p2<---
# | / \ |
# |--->c1_1 ------>c2_1
c1_1.switch(c2_1, None)
output.seek(0)
print output.read()
output.truncate(0)
if __name__ == '__main__':
test1()
test2()
test3()
test4()