天天看點

Lua 協同程式coroutine

前言

Lua協同程式: 開啟另一個邏輯處理和c#一樣,同一時間隻能有一個協同程式被執行

線程:同一時間,可以有多個線程執行

程序:線程的一個載體,一個程式的運作獨立為一個程序,程序和程序之間都有自己獨立的儲存單元、一個程序可以包含多個線程、多個線程之間共享存儲單元。

比如打開一個手機遊戲,這個遊戲就有一個程序,遊戲内部有很多線程同時運作,線程都有一個共享單元來擷取存儲資料

Lua中協同程式的所有函數都被放進一個叫coroutine的表(table)中

Lua中協同程式的4種狀态: 運作、挂起、死亡、正常

一、coroutine.create 建立協同程式

建立協同程式,create函數參數位數一個函數

該參數就是協同程式的工作函數,參數函數一般為匿名函數

create函數有一個傳回值->協同程式

local  c1 = coroutine.create(function()
    print("我是協同程式")
end)
           

二、coroutine.status檢視狀态

協同程式建立後預設為suspended挂起狀态,協同程式執行完變成dead死亡狀态

local  c1 = coroutine.create(function()
    print("我是協同程式")
end)
print(coroutine.status(c1)) --suspended 挂起
           

三、coroutine.resume 執行協同程式(開始協同程式)

local  c1 = coroutine.create(function()
    print("我是協同程式")
end)
print(coroutine.status(c1)) --suspended 挂起
coroutine.resume(c1) --執行協同程式(開始協同程式)
print(coroutine.status(c1)) -- dead 死亡結束
           

四、yield() 挂起

yield 和 c#差不多,停止協同程式,條件滿足繼續向下執行

local c2 = coroutine.create(function()
    for i =  , do
        print(i)
        coroutine.yield() -- 挂起,等待喚醒
        print("go on") -- 被挂起 go on 不再執行
    end
end)
coroutine.resume(c2)
print("LS")  -- 挂起後調用
print(coroutine.status(c2)) -- 挂起狀态
coroutine.resume(c2) --喚醒協程繼續向下執行,又被挂起了
print(coroutine.status(c2)) -- 挂起狀态
coroutine.resume(c2) --再次喚醒直接結束了(循環完了2次)
print(coroutine.status(c2)) -- dead結束狀态
           

五、resume: 方法有兩個傳回值

1.協同程式是否正确執行(正确true,錯誤false)

2. 錯誤原因(正确傳回nill, 錯誤傳回string)

local c3 = coroutine.create(function()
    print("協同程式")
    error("協同程式發生錯誤")--強制報錯,報錯原因是:協同程式發生錯誤
end
)
local result ,err = coroutine.resume(c3)
print(result)
print(err) -- 協同程式不會報錯,而是在這裡把錯誤原因列印出來
           

六、resume: 協同程式函數帶有參數

local c4 = coroutine.create(function(name,age)
    print(name)
    print(age)
end
)
coroutine.resume(c4,"Young",) -- 在調用協同程式後面按順序依次添加
           

七、resume: 函數第二個傳回值

如果協同程式發生錯誤,第二個傳回值為錯誤資訊

如果協同程式沒有發生錯誤,那麼

第二個傳回值為yield函數的參數

local c5 = coroutine.create(function()
    print("lua")
    --error("抛出異常") --測試錯誤情況
    coroutine.yield("挂起協同程式") --此處不會列印
end)

local result, err = coroutine.resume(c5)
print(result)
print(err) -- 列印傳回yield的參數:挂起協同程式
           

八、yield函數傳回值就是rusume函數的第二個參數

上面的例子可以說是:yield 函數的參數是resume函數的第二個傳回值

而現在這個例子說的是:yield 函數的傳回值是resume函數的第二個參數

有點複雜,可以根據例子來了解

local c6 = coroutine.create(function(name)
    local b = coroutine.yield("傳回給rusume函數")
    print(b)--列印A
end)
coroutine.resume(c6,"Y") --第一次"Y"是給協同程式的形參name作實參傳入,但是協同程式被yield挂起了
coroutine.resume(c6,"A") --第二次繼續執行協同程式,此時第二個參數”A“就是yiled函數的傳回值
           

九、協同程式中函數帶有傳回值

協同程式中函數的第一個傳回值給了resume函數的第二個傳回值上

下次繼續執行協同程式,resume函數傳回值依次為

true

nil

abc

hello lua

local c7 = coroutine.create(function()
    coroutine.yield("挂起協同程式")
    return nil, "abc", "hello lua"
end)

local result ,err = coroutine.resume(c7)
print(result) -- true
print(err) -- 挂起協同程式
local result , err, ret1, ret2 = coroutine.resume(c7)
print(result) -- true
print(err)  -- nil
print(ret1) --abc 
print(ret2) --hello lua
           

官方文檔案例

再讀讀官方文檔的例子,加深了解

yield 函數的參數是resume函數的第二個傳回值,(第一個傳回值是true)

resume函數的第二個參數是yield 函數的傳回值,(第一個參數是協同程式變量(函數)名)

function foo (a)
    print("foo", a)
    return coroutine.yield(*a)
end

co = coroutine.create(function (a,b)
      print("co-body", a, b) 
      local r = foo(a+) 
      print("co-body", r)
      local r, s = coroutine.yield(a+b, a-b)
      print("co-body", r, s)
      return b, "end"
end)

print("main", coroutine.resume(co, , ))
print("main", coroutine.resume(co, "r"))
print("main", coroutine.resume(co, "x", "y"))
print("main", coroutine.resume(co, "x", "y"))
           

列印結果:

When you run it, it produces the following output:

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