python greenlet

    greenlet是python的一个高性能的协程库,其底层用C实现.一个greenlet对象就代表一个协程.

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()




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值