解析關(guān)于Lua協(xié)同程序
關(guān)于Lua協(xié)同程序的內(nèi)容是本文要介紹的內(nèi)容,主要是來學(xué)習(xí)lua中線程的使用方法,關(guān)于系統(tǒng)程序,本文有詳解,具體內(nèi)容一起來看詳解。
1、什么是協(xié)同(coroutine)?
協(xié)同程序(coroutine)與線程比較類似:擁有獨(dú)立的堆棧,獨(dú)立的局部變量,獨(dú)立的指令指針,但是和其他協(xié)同程序共享全局變量等很多信息。
線程和協(xié)同程序的主要不同在于:在多處理器情況下,從概念上來講多線程程序同時(shí)運(yùn)行多個(gè)線程;而協(xié)同程序是通過協(xié)作來完成,在任一指定時(shí)刻只有一個(gè)協(xié)同程序在運(yùn)行,并且這個(gè)正在運(yùn)行的協(xié)同程序只有在明確的被要求掛起的時(shí)候才會(huì)被掛起。協(xié)作程序有點(diǎn)類似同步的多線程,在等待同一個(gè)線程鎖的幾個(gè)線程有點(diǎn)類似協(xié)同。
協(xié)同和順序執(zhí)行的區(qū)別?任一制定時(shí)刻只能運(yùn)行一個(gè)協(xié)同程序,這個(gè)和順序執(zhí)行區(qū)別在哪?關(guān)鍵在于yield函數(shù)。如果順序執(zhí)行的時(shí)候進(jìn)行耗費(fèi)cpu時(shí)間或者一直等待某個(gè)資源的時(shí)候,程序?qū)⒖ㄔ谶@個(gè)地方不能前進(jìn)。協(xié)同程序的出現(xiàn)就是可以使等待資源的線程讓出資源,進(jìn)行下一個(gè)協(xié)同程序的操作。yield可以在執(zhí)行出錯(cuò)的時(shí)候掛起,下次恢復(fù)的時(shí)候再進(jìn)行操作。
2、協(xié)同(coroutine)的幾個(gè)狀態(tài)
掛起態(tài):創(chuàng)建一個(gè)協(xié)同程序時(shí)他開始的狀態(tài)為掛起態(tài),函數(shù)coroutine.yield可以使程序由運(yùn)行態(tài)變?yōu)閽炱馉顟B(tài)
運(yùn)行態(tài):函數(shù)coroutine.resume可以使程序由掛起狀態(tài)變?yōu)檫\(yùn)行態(tài)
停止態(tài):協(xié)同程序結(jié)束,進(jìn)入停止態(tài)
3、coroutine.resume
resume可以給協(xié)同程序傳參數(shù),并將掛起態(tài)程序恢復(fù)為運(yùn)行態(tài)
- coroutinecoroutine.co = coroutine.create(function (a,b,c)
- print("co", a, b, c)
- end)
- coroutine.resume(co, 1, 2, 3) --> co 1 2 3resume
coroutine.resume直到線程結(jié)束或者遇到coroutine.yield時(shí)返回。
(1)coroutine.resume的參數(shù):線程函數(shù)***次運(yùn)行,參數(shù)作為線程函數(shù)參數(shù);如果yield沒有顯式返回參數(shù),則coroutine.resume的參數(shù)作為yield的額外參數(shù)返回。
(2)如果是掛起狀態(tài)(一開始也是掛起狀態(tài)),繼續(xù)運(yùn)行resume函數(shù)返回true;如果線程已經(jīng)停止或者遇到其他錯(cuò)誤,resume函數(shù)返回false及錯(cuò)誤信息。
(3)線程結(jié)束則線程主函數(shù)的返回值作為coroutine.resume的附加返回值。
這點(diǎn)特性很微妙,可以看出coroutine.resume其實(shí)是個(gè)阻塞函數(shù),阻塞等待協(xié)同程序完成或者yield退出。可以把協(xié)同程序當(dāng)成一個(gè)等待對(duì)象,對(duì)象等待返回則coroutine.resume返回。在coroutine.resume調(diào)用的地方阻塞調(diào)用線程,這個(gè)特性要記住!
4、coroutine.yield
yield可以返回額外參數(shù),或者掛起協(xié)同程序
- co = coroutine.create(function (a,b)
- coroutine.yield(a + b, a - b)
- end)
- print(coroutine.resume(co, 20, 10)) --> true 30 10
- co = coroutine.create (function ()
- print("co", coroutine.yield())
- end)
- coroutine.resume(co)
- coroutine.resume(co, 4, 5) --> co 4 5
使用函數(shù)yield可以使程序掛起并返回狀態(tài)給resume,當(dāng)我們激活被掛起的程序時(shí),yield返回(這里的返回是說從阻塞狀態(tài)返回)并繼續(xù)程序的執(zhí)行直到再次遇到y(tǒng)ield或者程序結(jié)束
5、對(duì)稱協(xié)同和不對(duì)稱協(xié)同
對(duì)稱協(xié)同:執(zhí)行到掛起之間狀態(tài)轉(zhuǎn)換的函數(shù)是相同的
不對(duì)稱協(xié)同:掛起一個(gè)正在執(zhí)行的協(xié)同的函數(shù)與使一個(gè)被掛起的協(xié)同再次執(zhí)行的函數(shù)是不同的(resum和yield)
6、消費(fèi)者驅(qū)動(dòng)的生產(chǎn)者-消費(fèi)者模型
當(dāng)消費(fèi)者需要值時(shí)他喚起生產(chǎn)者生產(chǎn)值,生產(chǎn)者生產(chǎn)值后停止直到消費(fèi)者再次請(qǐng)求。我們稱這種設(shè)計(jì)為消費(fèi)者驅(qū)動(dòng)的設(shè)計(jì)。平常多見的生產(chǎn)者-消費(fèi)者模型,是產(chǎn)品驅(qū)動(dòng)的設(shè)計(jì),生產(chǎn)者不斷生產(chǎn)產(chǎn)品,消費(fèi)者用臨界區(qū)保護(hù)取產(chǎn)品消費(fèi)
協(xié)同為解決這種問題提供了理想的方法,因?yàn)檎{(diào)用者與被調(diào)用者之間的resume-yield關(guān)系會(huì)不斷顛倒。當(dāng)一個(gè)協(xié)同調(diào)用yield時(shí)并不會(huì)進(jìn)入一個(gè)新的函數(shù),取而代之的是返回一個(gè)未決的resume的調(diào)用。相似的,調(diào)用resume時(shí)也不會(huì)開始一個(gè)新的函數(shù)而是返回yield的調(diào)用。這種性質(zhì)正是我們所需要的,與使得send-receive協(xié)同工作的方式是一致的:receive喚醒生產(chǎn)者生產(chǎn)新值,send把產(chǎn)生的值送給消費(fèi)者消費(fèi)。
- function receive (prod)
- local status, value = coroutine.resume(prod)
- return value
- end
- function send (x)
- coroutine.yield(x)
- end
- function producer ()
- return coroutine.create(function ()
- while true do
- local x = io.read() -- produce new value
- send(x)
- end
- end)
- end
- function filter (prod)
- return coroutine.create(function ()
- local line = 1
- while true do
- local x = receive(prod) -- get new value
- x = string.format("%5d %s", line, x)
- send(x) -- send it to consumer
- lineline = line + 1
- end
- end)
- end
- coroutine.resumefunction consumer (filter)
- while true do
- local x = receive(filter) -- get new value
- io.write(x, "\n") -- consume new value
- end
- end
- p = producer()
- f = filter(p)
- consumer(f)
看完上面這個(gè)例子你可能很自然的想到UNIX的管道,協(xié)同是一種非搶占式的多線程。管道的方式下,每一個(gè)任務(wù)在獨(dú)立的進(jìn)程中運(yùn)行,而協(xié)同方式下,每個(gè)任務(wù)運(yùn)行在獨(dú)立的協(xié)同代碼中。管道在讀(consumer)與寫(producer)之間提供了一個(gè)緩沖,因此兩者相關(guān)的的速度沒有什么限制,在上下文管道中這是非常重要的,因?yàn)樵谶M(jìn)程間的切換代價(jià)是很高的。協(xié)同模式下,任務(wù)間的切換代價(jià)較小,與函數(shù)調(diào)用相當(dāng),因此讀寫可以很好的協(xié)同處理。
小結(jié):解析關(guān)于Lua協(xié)同程序的內(nèi)容介紹完了,希望通過本文的學(xué)習(xí)能對(duì)你有所幫助!