這期內(nèi)容當(dāng)中小編將會(huì)給大家?guī)?lái)有關(guān)Lua coroutine不一樣的多線程編程思路是什么,文章內(nèi)容豐富且以專業(yè)的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。
創(chuàng)新互聯(lián)建站是一家專業(yè)提供太倉(cāng)企業(yè)網(wǎng)站建設(shè),專注與成都網(wǎng)站設(shè)計(jì)、做網(wǎng)站、成都h5網(wǎng)站建設(shè)、小程序制作等業(yè)務(wù)。10年已為太倉(cāng)眾多企業(yè)、政府機(jī)構(gòu)等服務(wù)。創(chuàng)新互聯(lián)專業(yè)網(wǎng)站設(shè)計(jì)公司優(yōu)惠進(jìn)行中。
Lua中的coroutine是一種很好的設(shè)計(jì)模式,但我初步的體會(huì)還是沒(méi)想到其他語(yǔ)言和場(chǎng)合能非常適合用到coroutine的場(chǎng)景。
協(xié)同程序與線程差不多,也就是一條執(zhí)行序列,擁有自己獨(dú)立的棧,局部變量和指令指針,同時(shí)又與其它協(xié)同程序共享全局變量和其它大部分東西。線程與協(xié)同程序的主要區(qū)別在于,一個(gè)具有多線程的程序可以同時(shí)運(yùn)行幾個(gè)線程,而協(xié)同程序卻需要彼此協(xié)作地運(yùn)行。就是說(shuō),一個(gè)具有多個(gè)協(xié)同程序的程序在任何時(shí)刻只能運(yùn)行一個(gè)協(xié)同程序,并且正在運(yùn)行的協(xié)同程序只會(huì)在其顯示地掛起時(shí),它的執(zhí)行才會(huì)暫停。
如:
co = coroutine.create(function () for i=1,10 do print("co", i) coroutine.yield() end end)
從主線程調(diào)用
coroutine.resume(co)
會(huì)依次打印1到10
coroutine創(chuàng)建的所謂的“線程”都不是真正的操作系統(tǒng)的線程,實(shí)際上是通過(guò)保存stack狀態(tài)來(lái)模擬的。
由于是假的線程,所以切換線程的開(kāi)銷(xiāo)極小,同時(shí)創(chuàng)建線程也是輕量級(jí)的,new_thread只是在內(nèi)存新建了一個(gè)stack用于存放新coroutine的變量,也稱作lua_State
LUA_API lua_State *lua_newthread (lua_State *L)
調(diào)用yield()當(dāng)前線程交出控制權(quán),同時(shí)還可以通過(guò)stack返回參數(shù)。調(diào)用resume的線程(可理解為主線程)獲得返回的參數(shù)。
Lua yield()和Java中的Thread.yield()有點(diǎn)相似,但是區(qū)別更大。Java中的yield調(diào)用后只是將當(dāng)前CPU切換到另外一個(gè)線程,CPU可能隨時(shí)會(huì)繼續(xù)回到線程執(zhí)行。
我更傾向于把Lua中的yield()和resume()和Java中的wait()和notify()來(lái)對(duì)比。它們表現(xiàn)的行為基本一致。
關(guān)于stack實(shí)現(xiàn)也可參看Yufeng(Erlang高手)的分析文章 lua coroutine是如何實(shí)現(xiàn)的?
上面對(duì)coroutine有個(gè)基本的了解,因此大家都會(huì)象我一樣去想,為什么要用coroutine?先研究下優(yōu)點(diǎn)
每個(gè)coroutine有自己私有的stack及局部變量。
同一時(shí)間只有一個(gè)coroutine在執(zhí)行,無(wú)需對(duì)全局變量加鎖。
順序可控,完全由程序控制執(zhí)行的順序。而通常的多線程一旦啟動(dòng),它的運(yùn)行時(shí)序是沒(méi)法預(yù)測(cè)的,因此通常會(huì)給測(cè)試所有的情況帶來(lái)困難。所以能用coroutine解決的場(chǎng)合應(yīng)當(dāng)優(yōu)先使用coroutine。
再看缺點(diǎn),研究coroutine缺點(diǎn)之前,我尋找了一下Lua中為什么實(shí)現(xiàn)coroutine的一些說(shuō)明。在巴西人寫(xiě)的paper Coroutines in Lua(pdf)中解釋了幾個(gè)原因:
Lua是ANSI C實(shí)現(xiàn)的,ANSI C并不包含thread的實(shí)現(xiàn),因此如果要在Lua增加thread的支持就要使用操作系統(tǒng)本地的實(shí)現(xiàn),這樣會(huì)造成通用的問(wèn)題。同時(shí)也會(huì)使Lua變得臃腫。因此Lua選擇了在ANSI C上實(shí)現(xiàn)的coroutine。
Lua主要設(shè)計(jì)目的之一是給C調(diào)用,如果Lua內(nèi)部又有多線程實(shí)現(xiàn)的話會(huì)造成C調(diào)用狀態(tài)的混亂,而只提供coroutine層面的掛起則可以保持狀態(tài)的一致性。
以上這些理由都是基于Lua特殊的原因而使用的,并不是很通用的原因。我們也了解到,coroutine實(shí)際上是一種古老的設(shè)計(jì)模式,它在60年代就已經(jīng)定型,但是現(xiàn)代語(yǔ)言很少有重視這個(gè)特性,目前可以舉例的有Windows的fibers, Python的generators
上面優(yōu)點(diǎn)有1條沒(méi)展開(kāi),就是每個(gè)coroutine有自己私有的stack及內(nèi)存變量空間。因此可以認(rèn)為coroutine和Erlang中的process是非常相似的。但是coroutine只能同時(shí)只有一個(gè)在執(zhí)行,如果能讓他多個(gè)同時(shí)跑,我覺(jué)得就和Erlang非常相似了。
Lua程序設(shè)計(jì)介紹的一種實(shí)現(xiàn)方法,讓多個(gè)c threads啟動(dòng),然后每個(gè)c thread啟動(dòng)一個(gè)coroutine(類(lèi)似Erlang process),然后通過(guò)stack傳遞變量值(類(lèi)似Erlang process message),這樣就可以實(shí)現(xiàn)一個(gè)類(lèi)似Erlang的process模型了。由于coroutine實(shí)際上可以用任何語(yǔ)言實(shí)現(xiàn),那其他語(yǔ)言應(yīng)該也可實(shí)現(xiàn)同樣這種設(shè)計(jì)方法。
Lua目前主要用在游戲編程領(lǐng)域,通常的觀點(diǎn)Lua是“膠水語(yǔ)言”。用來(lái)把各個(gè)模塊化的功能粘合起來(lái)。就我目前閱讀的一些代碼來(lái)看,C和Lua通常是混合在一起的,并沒(méi)有明確的邊界。對(duì)于我一個(gè)外行的眼光看來(lái)我分不清哪些是在做C的事情,哪些是在調(diào)用Lua。特別是這個(gè)“膠水”如果放得太多,系統(tǒng)中各個(gè)模塊的獨(dú)立性將會(huì)受到影響。比如云風(fēng)的這篇Lua 不是 C++也提到,“這屬于過(guò)厚的粘合層,是絕對(duì)需要拋棄的”。
另外Code@Pig一篇[網(wǎng)游設(shè)計(jì)] 一點(diǎn)感想也提到要簡(jiǎn)化調(diào)用,我總結(jié)它的觀點(diǎn)主要兩點(diǎn):
不要存在冗余的關(guān)系,給一個(gè)部分負(fù)責(zé)管理就好。(由Lua/python來(lái)管理)
粘合層(Lua/python接口)不要過(guò)胖,我們可以通過(guò)引入一個(gè)“間接層”來(lái)把粘合層做“薄”
雖然Lua的高效和精簡(jiǎn)的設(shè)計(jì)讓人贊譽(yù)有加,但是它的性能排名并不高,和Python大致在同一個(gè)級(jí)別。另外“膠水語(yǔ)言”的定位也妨礙了它在更多領(lǐng)域的發(fā)展。
上述就是小編為大家分享的Lua coroutine不一樣的多線程編程思路是什么了,如果剛好有類(lèi)似的疑惑,不妨參照上述分析進(jìn)行理解。如果想知道更多相關(guān)知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。