Lua 程式設計 協程

2021-09-26 06:53:39 字數 3601 閱讀 7045

乙個協程(coroutine)與執行緒(thread,這裡指「多執行緒」中的執行緒)類似:它是乙個執行序列,擁有自己的棧,區域性變數,指令指標,但是與其他的協程共享全域性變數和其他大部分東西。

從概念上講,協程與執行緒最大的區別是:在乙個多處理器機器上,乙個多執行緒程式可以並行地執行多個執行緒。而協程是協作性的,乙個程式任意時刻只能執行乙個協程,並且只有這個協程在顯示地要求掛起時,它的執行才會暫停。

lua 將所有協程的函式放在乙個名為 「coroutine」 的 table 中。其中create函式用於建立乙個協程,它的引數是乙個函式。create 函式會返回乙個 thread 型別的值表示協程。

乙個協程可以處於4種不同的狀態:「掛起」、「執行」、「死亡」和「正常」。使用 status 函式可以檢視乙個協程的狀態。

協程剛建立時處於掛起狀態,使用resume函式可以啟動或再次執行協程,這時它的狀態是執行。

當協程執行的函式返回後,協程處於死亡狀態。

看下面乙個例子:

co = coroutine.create(function () print("hello world") end)

print(co)

print(coroutine.status(co))

coroutine.resume(co)

print(coroutine.status(co))

print(coroutine.resume(co))

輸出如下:

thread: 0x1f3c080 

suspended

hello world

dead

false cannot resume dead coroutine

**最後一行試圖再次執行乙個處於死亡狀態的協程,這時resume函式返回第乙個值為false,表示執行過程出錯,第二個值是乙個錯誤描述。

上面的例子僅僅是將協程當作乙個普通的函式使用,實際上協程的強大之處在於函式yield的使用上。這個函式可以讓協程掛起,之後可以使用resume函式恢復它的執行。

看個例子:

co = coroutine.create(function()

for i=1, 5 do

print("co", i)

coroutine.yield(i)

endprint("ok")

end)

coroutine.resume(co)

coroutine.resume(co)

coroutine.resume(co)

coroutine.resume(co)

coroutine.resume(co)

coroutine.resume(co)

輸出如下:

co      1

co 2

co 3

co 4

co 5

ok

程式最後一次呼叫resume函式時,協程函式執行完最後一次 for 迴圈中的yield函式,然後列印出「ok」,函式返回,協程處於死亡狀態。

從協程的角度看,所有在它掛起發生的活動都發生在 yield 呼叫中。當恢復協程的執行時,對於 yield 的呼叫才最終返回,然後協程執行執行,直到下乙個 yield 呼叫或函式返回。

當乙個協程 a 喚醒另乙個協程 b 時,a 既不是在掛起狀態也不是在執行狀態,我們稱這個特殊狀態為「正常」狀態。

協程還有一項有用的機制,就是可以通過一對 resume-yield 呼叫來交換資料。resume 函式返回的值是執行 yield 函式時實參的值,yield 函式返回的值是執行 resume 函式時傳遞的引數值。

看如下的例子:

co = coroutine.create(function (a,b)

print("co1", coroutine.yield(a + b, a - b))

print("co2", coroutine.yield(a - b, a + b))

end)

print(coroutine.resume(co, 20, 10))

print(coroutine.resume(co, 10, 5))

print(coroutine.resume(co, 20, 10))

輸出如下:

true    30      10

co1 10 5

true 10 30

co2 20 10

true

第一次呼叫 resume 函式時,傳遞的引數是20和10,由於協程沒有執行過,這些引數會作為協程函式的引數,所以協程函式實參 a 的值為20,實參 b 的值為10,當執行第乙個 yield 函式時(它的實參的值計算後是30和10),協程掛起(yield 函式並沒有返回!)。那麼 yield 函式實參的值作為 resume 函式的返回值。我們看到程式輸出「true 30 10」。

第二次呼叫 resume 函式時,傳遞的引數是10和5,由於協程正處於掛起狀態,因此這些引數被傳遞給第乙個 yield 函式作為它的返回值,協程被喚醒後,第乙個 yield 函式返回,執行完第乙個 print 函式後,程式輸出「co1 10 5」,接著執行第二個 yield 函式時,協程被掛起。resume 函式的返回值是執行第二個 yield 函式時實參的值,也就是10和30,程式輸出「true 10 30」。

最後一次呼叫 resume 函式時,傳遞的引數是20和10,使協程從第二個 yield 函式中返回,之後協程函式返回,由於協程函式沒有返回任何值,所以我們只看到程式輸出「true」。

乙個關於協程使用的經典示例就是「生產者和消費者」問題。這其中涉及到兩個函式,乙個函式不斷地產生值,乙個函式不斷地消費值。示例**如下:

producer = coroutine.create(

function ()

while true do

local x = io.read()

send(x)

endend

)function consumer ()

while true do

local x = receive()

io.write(x, "\n")

endendfunction receive ()

local status, value = coroutine.resume(producer)

return value

endfunction send (x)

coroutine.yield(x)

endconsumer()

示例中,生產者函式作為乙個協程,主程式直接執行消費者函式。當消費者需要乙個值時,它啟動或喚醒生產者協程,生產者產生乙個值後,掛起自己,將值傳遞給消費者。

Lua協程例子

lua的協程是好東西,跟unity的協程還是不太一樣,下面寫了乙個例子,直接上 co coroutine.create function body print hi coroutine end print type co print coroutine.status co coroutine.res...

Lua學習 協程

print 協同程式 print 協程的建立 常用方式 coroutine.create fun function print 123 end co coroutine.create fun 協程的本質是乙個執行緒物件 print co print type co coroutine.wrap co...

lua協程再探

lua語言的協程中yield關鍵字可以掛起當前coroutine執行,並暫時儲存臨時變數值,該值即是第二次呼叫 resume 時傳入的引數!co coroutine.create function value1,value2 local tempvar3 10 print coroutine sec...