lua coroutine & skynet
1.luaでのコンシステント
thread type
OSのthreadと同じ概念ではないコパスを作成するために使用されます
Pythonは異なり、PythonのスレッドはOSのオリジナルスレッドである.しかしstacklessとpypyのマイクロスレッドはこの概念とあまり差がありません
Coroutines
別名collaborative multithreading(コラボレーションマルチスレッド)
各スレッドは独立したスレッド(lua thread,not os thread)であり、現在のスレッドはyieldが明示的に呼び出された場合にのみ停止します.
coroutine.create(..)コンボを作成します.パラメータ:コンボが実行するmain関数;戻り値:threadオブジェクト、コパスを指すthreadオブジェクト
coroutine.resume(..)最初のパラメータはthreadオブジェクト
起動時に他のパラメータがコヒーレントに対応するmain関数に渡されます
リカバリ時に割り込み時のyieldに他のパラメータを割り当てるオブジェクト
coroutine.yield(..)コンシステントが停止し、coroutine.resume()はすぐに戻り、値を返します:true+yieldのパラメータ;
次回resume時にこのポイントから実行を再開
The next time you resume the same coroutine, it continues its execution from the point where it yielded, with the call to coroutine.yield returning any extra arguments passed to coroutine.resume.
coroutine.wrap(..)コンボを作成します.パラメータ:コンボが実行するmain関数;戻り値:function、functionの呼び出しはcoroutineに等しい.resume(..),パラメータがコヒーレントmain関数に渡される
cotoutine.resume(..)の主な違いはエラーをキャプチャしないで、エラーは上へ伝播して、戻り値は最初のbooleanがありません.
実ははっきり言ってmain関数に対して1つの包装をして、表示の呼び出しresumeを使わないで、元の関数のように多く使うことができます
プロセス終了:
1.コンシステントによって実行される関数の終了、この場合coroutine.resume()はtrue+コヒーレンス関数の戻り値を返します
2.コンシステントで実行する関数に保護されていないエラーが発生しました.resume()はfalse+エラー情報を返します
EXAMPLE:
2.skynet対協程の改造過程:はっきり言ってluaをデフォルトのcoroutine.ここにいるよyieldはupvalueとしてDIYのlresumeとlyieldに打ち込み、コモンスタート時間と累積運転時間をupvalueとしてlstart/lstop/lresume/lyieldに打ち込む
thread type
OSのthreadと同じ概念ではないコパスを作成するために使用されます
Pythonは異なり、PythonのスレッドはOSのオリジナルスレッドである.しかしstacklessとpypyのマイクロスレッドはこの概念とあまり差がありません
Coroutines
別名collaborative multithreading(コラボレーションマルチスレッド)
各スレッドは独立したスレッド(lua thread,not os thread)であり、現在のスレッドはyieldが明示的に呼び出された場合にのみ停止します.
coroutine.create(..)コンボを作成します.パラメータ:コンボが実行するmain関数;戻り値:threadオブジェクト、コパスを指すthreadオブジェクト
coroutine.resume(..)最初のパラメータはthreadオブジェクト
起動時に他のパラメータがコヒーレントに対応するmain関数に渡されます
リカバリ時に割り込み時のyieldに他のパラメータを割り当てるオブジェクト
coroutine.yield(..)コンシステントが停止し、coroutine.resume()はすぐに戻り、値を返します:true+yieldのパラメータ;
次回resume時にこのポイントから実行を再開
The next time you resume the same coroutine, it continues its execution from the point where it yielded, with the call to coroutine.yield returning any extra arguments passed to coroutine.resume.
coroutine.wrap(..)コンボを作成します.パラメータ:コンボが実行するmain関数;戻り値:function、functionの呼び出しはcoroutineに等しい.resume(..),パラメータがコヒーレントmain関数に渡される
cotoutine.resume(..)の主な違いはエラーをキャプチャしないで、エラーは上へ伝播して、戻り値は最初のbooleanがありません.
実ははっきり言ってmain関数に対して1つの包装をして、表示の呼び出しresumeを使わないで、元の関数のように多く使うことができます
プロセス終了:
1.コンシステントによって実行される関数の終了、この場合coroutine.resume()はtrue+コヒーレンス関数の戻り値を返します
2.コンシステントで実行する関数に保護されていないエラーが発生しました.resume()はfalse+エラー情報を返します
EXAMPLE:
[dongsong@localhost skynet]$ lua
Lua 5.1.4 Copyright (C) 1994-2008 Lua.org, PUC-Rio
> =coroutine
table: 0x113f600
> for k,v in pairs(coroutine) do print(k,v) end
resume function: 0x113f830
yield function: 0x113f9b0
status function: 0x113f8f0
wrap function: 0x113f950
create function: 0x113e2e0
running function: 0x113f890
[dongsong@localhost lua-study]$ cat coroutine.lua
function foo (a)
print("foo", a)
return coroutine.yield(2*a) --resume returned: true 4
end
co = coroutine.create(function (a,b)
print("co-body", a, b)
local r = foo(a+1)
print("co-body", r)
local r, s = coroutine.yield(a+b, a-b) --resume returned: true 11 -9
print("co-body", r, s)
return b, "end" --resume returned: true 10 end
end)
print("main", coroutine.resume(co, 1, 10)) --main true 4
print("main", coroutine.resume(co, "r")) --main true 11 -9
print("main", coroutine.resume(co, "x", "y")) --main true 10 end
print("main", coroutine.resume(co, "x", "y")) --main false cannot resume dead coroutine
[dongsong@localhost lua-study]$
[dongsong@localhost lua-study]$ lua coroutine.lua
co-body 1 10
foo 2
main true 4
co-body r
main true 11 -9
co-body x y
main true 10 end
main false cannot resume dead coroutine
2.skynet対協程の改造過程:はっきり言ってluaをデフォルトのcoroutine.ここにいるよyieldはupvalueとしてDIYのlresumeとlyieldに打ち込み、コモンスタート時間と累積運転時間をupvalueとしてlstart/lstop/lresume/lyieldに打ち込む
int
luaopen_profile(lua_State *L) {
luaL_checkversion(L);
luaL_Reg l[] = {
{ "start", lstart },
{ "stop", lstop },
{ "resume", lresume },
{ "yield", lyield },
{ NULL, NULL },
};
luaL_newlibtable(L,l);
lua_newtable(L); // table thread->start time
lua_newtable(L); // table thread->total time
/*
* table -> total time
* table -> start time
* table -> libtable
*/
lua_newtable(L); // weak table
lua_pushliteral(L, "kv");
lua_setfield(L, -2, "__mode");
/*
* table -> weak table
* table -> total time
* table -> start time
* table -> libtable
*/
lua_pushvalue(L, -1);
lua_setmetatable(L, -3);
lua_setmetatable(L, -3);
/*
* table -> total time with weak metatable
* table -> start time with weak metatable
* table -> libtable
*/
lua_pushnil(L);
luaL_setfuncs(L,l,3);
/*
* table -> libtable: {start=lstart, stop=lstop, resume=lresume, yield=lyield};
* upvalues of lstart/lstop/lresume/lyield: table->starttime, table->totaltime, nil
*/
int libtable = lua_gettop(L); //libtable = 1
lua_getglobal(L, "coroutine"); // lua coroutine
lua_getfield(L, -1, "resume"); // lua coroutine.resume
lua_CFunction co_resume = lua_tocfunction(L, -1); //co_resume=lua coroutine.resume
if (co_resume == NULL)
return luaL_error(L, "Can't get coroutine.resume");
lua_pop(L,1); // lua coroutine.resume stack
/*
* coroutine (lua coroutine table)
* table -> libtable: {start=lstart, stop=lstop, resume=lresume, yield=lyield};
* upvalues of lstart/lstop/lresume/lyield: table->starttime, table->totaltime, nil
*/
lua_getfield(L, libtable, "resume");
/*
* cfunction lresume
* coroutine (lua coroutine table)
* table -> libtable: {start=lstart, stop=lstop, resume=lresume, yield=lyield};
* upvalues of lstart/lstop/lresume/lyield: table->starttime, table->totaltime, nil
*/
lua_pushcfunction(L, co_resume);
/*
* cfunction co_resume (lua default coroutine.resume)
* cfunction lresume
* coroutine (lua coroutine table)
* table -> libtable: {start=lstart, stop=lstop, resume=lresume, yield=lyield};
* upvalues of lstart/lstop/lresume/lyield: table->starttime, table->totaltime, nil
*/
lua_setupvalue(L, -2, 3);
/*
* cfunction lresume with upvalues: table->starttime, table->totaltime, co_resume (coroutine.resume)
* coroutine (lua coroutine table)
* table -> libtable: {start=lstart, stop=lstop, resume=lresume, yield=lyield};
* upvalues of lstart/lstop/lyield: table->starttime, table->totaltime, nil
* upvalues of lresume: table->starttime, table->totaltime, co_resume (coroutine.resume)
*/
lua_pop(L,1);
/*
* coroutine (lua coroutine table)
* table -> libtable: {start=lstart, stop=lstop, resume=lresume, yield=lyield};
* upvalues of lstart/lstop/lyield: table->starttime, table->totaltime, nil
* upvalues of lresume: table->starttime, table->totaltime, co_resume (coroutine.resume)
*/
lua_getfield(L, -1, "yield");
lua_CFunction co_yield = lua_tocfunction(L, -1); //co_yield=coroutine.yield
if (co_yield == NULL)
return luaL_error(L, "Can't get coroutine.yield");
lua_pop(L,1);
/*
* coroutine (lua coroutine table)
* table -> libtable: {start=lstart, stop=lstop, resume=lresume, yield=lyield};
* upvalues of lstart/lstop/lyield: table->starttime, table->totaltime, nil
* upvalues of lresume: table->starttime, table->totaltime, co_resume (coroutine.resume)
*/
lua_getfield(L, libtable, "yield");
lua_pushcfunction(L, co_yield);
lua_setupvalue(L, -2, 3);
/*
* cfunction lyield with upvalues: table->starttime, table->totaltime, co_yield (coroutine.yield)
* coroutine (lua coroutine table)
* table -> libtable: {start=lstart, stop=lstop, resume=lresume, yield=lyield};
* upvalues of lstart/lstop: table->starttime, table->totaltime, nil
* upvalues of lresume: table->starttime, table->totaltime, co_resume (coroutine.resume)
* upvalues of lyield: table->starttime, table->totaltime, co_yield (coroutine.yield)
*/
lua_settop(L, libtable);
/*
* table -> libtable: {start=lstart, stop=lstop, resume=lresume, yield=lyield};
* upvalues of lstart/lstop: table->starttime, table->totaltime, nil
* upvalues of lresume: table->starttime, table->totaltime, co_resume (coroutine.resume)
* upvalues of lyield: table->starttime, table->totaltime, co_yield (coroutine.yield)
*/
return 1;
}