Pythonゲームサーバ開発日記(三)greenletシミュレーションlua coroutineの研究

1975 ワード

分散システムでは、1つのEntityが他のEntityにアクセスする場合、この呼び出しは一般的に非同期であり、すなわち、その時点ですぐに戻り値を得ることができない.callbackで実現すると、関数が細かくなります.
skynetはコア層でこの問題を処理し、skynetを提供した.callは非同期呼び出しをします.
私の研究によるとPython 2.xはジェネレータ(generator)がcoroutineをシミュレートする方法を提供するが,明らかに不完全であり,コヒーレントなジャンプ,管理が実用的なレベルに達することは困難である.
Python 3はasyncioの方法を提供していて、私たちの応用にとって、少し重すぎて、私はその原理をよく理解していませんが、実現の中にthread関連のものがあるのを見て、私たちが望んでいる簡単なcoroutineに修正するのが難しいと予感しました.
幸いグリーンレットがあって、2日間の試みを経て、やっと正しい使い方を見つけた.
この多くの経験のある人は理解していないと言っていますが、ここの使い方はゲームエンジンの設計構想と関係があり、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と同じプロセスのプログラムと完全に同じです.
このプログラムに書いてからpython 2を知った.xのprint機能は確かに「正しくない」ので、python 3をprint()関数に変更して実現するのも無理はない.理由は次のように考えられます.
-------------------------2015-9-2再補充----------------------------------------------
暇を見つけてerlangの入門を見てみると、coroutine(協程)は本当に重要で、erlangが成功した同時言語になることができたのは、変数をキャンセルしたからだけではない.もう一つの重要な原因はerlangが天然にcoroutineを持っており、文法的にcoroutineをサポートしていることです.luaやpythonのような理解しにくいコラボレーションではなく、