Python游戏服务器开发日记(三)用greenlet模拟lua coroutine的研究

        分布式系统中,如果一个Entity访问其他Entity,那么这个调用一般都是异步的,也就是说当时不能立即得到返回值。如果用callback的方式实现,函数就会变得很碎。

        skynet在核心层处理了这个问题,并提供了skynet.call来做异步调用。


        据我研究,Python2.x提供了生成器(generator)模拟coroutine的方法,但是显然是不完备的,协程的跳转、管理很难达到实用水准。

        Python3提供了asyncio的方法,对我们的应用来说,有点过重了,我不太理解其原理,但是看到实现里面有一些thread相关的东西,预感到很难将其修改为我们想要的简单coroutine。

        好在有greenlet,经过两天的尝试之后,才找到了正确用法。


        这块很多有经验的人表示不理解,这里的用法和游戏引擎的设计思路有关,在web开发中很难找到相同的问题域(用Python做深度开发的还是web领域比较多)。一般来说,协程只要提供让出执行流的功能,在很多情况下就够用了。但是我们是用在协程交互里,必须加上“返回值”的功能,导致问题不一样了。


        而且这里对协程的使用,并非是出于并发和效率的考虑,而仅仅是简化逻辑代码的考虑(防止callback、防止琐碎的函数),仅仅用于保存上下文方便重入。


     

from greenlet import greenlet, getcurrent

def log( *c ):
    print " ".join( [str(i) for i in c] )

def co_yield( *c ):
    return getcurrent().parent.switch( *c )

def foo( a ):
    log( "foo", a )
    return co_yield( 2*a )

def co( a,b ):
    log( "co-body", a, b )
    r = foo( a+1 )
    log( "co-body r", r )
    r,s = co_yield( a+b, a-b )
    log( "co-body r s", r, s )
    return b, "end"

gr_main = greenlet( co )
log( "main", gr_main.switch( 1, 10 ) )
log( "main", gr_main.switch( "r" ) )
log( "main", gr_main.switch( "x", "y" ) )
log( "main", gr_main.switch( "other" ) )


        上面的代码是刚刚手敲的。如果有笔误稍改一下即可。运行结果与lua coroutine相同过程的程序完全相同。

        写到这个程序,才知道python2.x的print功能确实是不“正确”的,怪不得python3改为print()函数实现。原因可以想想  :)




------------------------2015-9-2 再次补充--------------------------

        抽空看了一下erlang入门,发现其实coroutine(协程)实在是太重要了,erlang能够成为成功的并发语言,不光是因为它取消了变量等原因。还有一个重要原因是erlang天然的具有coroutine,而且从语法上就支持了coroutine。而不是lua或者python这样难以理解的协程、

        

你可能感兴趣的:(编程,python,大作)