協同程序(coroutine)簡介
Lua 協同程序(coroutine)與線程比較類似:擁有獨立的堆棧,獨立的局部變量,獨立的指令指針,同時又與其它協同程序共享全局變量和其它大部分東西。
線程和協同程序區別
1.線程可以同時運行,協同程序卻需要彼此協作的運行。
2.在任一指定時刻只有一個協同程序在運行,並且這個正在運行的協同程序只有在明確的被要求掛起的時候纔會被掛起。
協同程序有點類似與,在等待同一個線程鎖的幾個線程。
方法概覽
方法 | 描述 |
coroutine.create(func) |
創建coroutine,該方法只創建,如需喚醒coroutine需配合resume方法; 入參:是協程運行的函數; 返回:成功返回coroutine。 |
coroutine.resume(co, val1, ...) |
喚醒coroutine,和create配合使用; 入參:可任意輸入,但是第一個入參必須是coroutine.create()的返回值。 1.如果是第一次喚醒,其餘入參作爲協程運行函數的入參。多餘的參數被捨棄。 2.如果是喚醒調用yield()掛起的協程,其他輸入參數將作爲yield()的返回值。 除第一個入參外,如果入參個數少於yield()返回值個數,則執行失敗,如果多於yield()返回 值個數,則多餘的參數被捨棄,執行成功; 返回:成功返回true與yield()的入參。失敗返回錯誤提示。 |
coroutine.yield(val1, ...) |
掛起coroutine,和resume配合使用能有很多有用的效果; 入參:可以任意輸入,輸入的入參將作爲resume的返回值; 返回:resume()的入參作。 |
coroutine.status(co) |
獲取coroutine的狀態; 入參:coroutine.create()的返回值; 返回:返回coroutine的狀態有四種:dead,suspend,running,normal。 |
coroutine.wrap(func) |
創建coroutine,返回一個函數,一旦你調用這個函數,就進入coroutine,和create功能重複; 入參:是協程運行的函數; 返回:成功返回一個函數。 |
coroutine.running() | 返回:正在跑的coroutine,一個coroutine就是一個線程,當使用running的時候,就是返回一個corouting的線程號 |
方法詳解
1. coroutine.create(func)
創建一個主體函數爲 func 的新協程。 func 必須是一個 Lua 的函數。 返回這個新協程,它是一個類型爲 "thread" 的對象。不會啓動該協程。
local co = coroutine.create(
function()
print("this is a coroutine")
return "coroutine return"
end)
print(co)
print(coroutine.resume(co))
輸出:
2. coroutine.resume(co, val1, ...)與coroutine.yield(val1, ...)
coroutine.resume(co, val1, ...),開始或喚醒協程co的運行。
- 如果第一次執行一個協程時,他會從協程函數開頭處開始運行。val1,...這些值會以參數形式傳入主體函數。
- 如果該協程被掛起,resume 會重新啓動它; val1, ... 這些參數會作爲掛起點(yield)的返回值。
- 如果協程運行起來沒有錯誤,將運行到協程掛起或協程結束, resume 返回 true 加上傳給 yield 的所有值 (當協程掛起), 或是主體函數的所有返回值(當協程中止)。
coroutine.yield(val1, ...),掛起正在調用的協程的執行。 傳遞給 yield 的參數都會轉爲 resume 的額外返回值。
local co = coroutine.create(
function (input)
print("input : "..input)
local param1, param2 ,param3 = coroutine.yield("yield1", "learning1")
print("param1 is : " .. param1)
print("param2 is : " .. param2)
print("param3 is : " .. param3)
local param4, param5 = coroutine.yield("yield2", "learning2")
print("param4 is : " .. param4)
print("param5 is : " .. param5)
-- return 也會將結果返回給 resume
return "coroutine return" , 1+2
end)
--第一次執行,將參數傳給input
print("first resume",coroutine.resume(co, "coroutine function"))
print("this is main chunk")
--第二次執行,將參數作爲yield的返回值,傳給param1 param2 param3
print("second resume",coroutine.resume(co, "param1", "param2", "param3"))
--第三次執行,將參數作爲yield的返回值,傳給param4 param5 多餘的param6被捨棄
print("third resume",coroutine.resume(co, "param4", "param5", "param6"))
輸出:
分析:
- 第一次調用resume,將協同程序喚醒,入參作爲函數入參;
- 協同程序運行;
- 運行到yield語句;
- yield掛起協同程序,第一次resume返回,,resume操作成功返回true,否則返回false;(注意:此處yield入參(yield1、learning1)是resume的返回值)
- 第二次調用resume,將協同程序喚醒,入參(param1, param2 ,param3)作爲yield的返回值 ;
- 協同程序運行;
- 運行到yield語句;
- yield掛起協同程序,第二次resume返回,,resume操作成功返回true,否則返回false;(注意:此處yield入參(yield2、learning2)是resume的返回值)
- ...
3. coroutine.status(co)
以字符串形式返回協程 co 的狀態:
- 當協程正在運行(它就是調用 status 的那個) ,返回 "running";
- 如果協程調用 yield 掛起或是還沒有開始運行,返回 "suspended";
- 如果協程是活動的,都並不在運行(即它正在延續其它協程),返回 "normal";
- 如果協程運行完主體函數或因錯誤停止,返回 "dead"。
local co
local co2 = coroutine.create(function() print("3."..coroutine.status(co)) end)
co = coroutine.create(
function ()
print("2."..coroutine.status(co))
coroutine.resume(co2)
coroutine.yield()
end)
print("1."..coroutine.status(co))
coroutine.resume(co)
print("4."..coroutine.status(co))
coroutine.resume(co)
print("5."..coroutine.status(co))
輸出:
4. coroutine.wrap(func)
創建一個主體函數爲 func 的新協程。func 必須是一個 Lua 的函數。返回一個函數,每次調用該函數都會延續該協程(不需要調用resume)。傳給這個函數的參數都會作爲 resume 的額外參數。和 resume 返回相同的值,只是沒有第一個布爾量。
local wrap = coroutine.wrap(
function (input)
print("input : "..input)
local param1, param2 ,param3 = coroutine.yield("yield1", "learning1")
print("param1 is : " .. param1)
print("param2 is : " .. param2)
print("param3 is : " .. param3)
local param4, param5 = coroutine.yield("yield2", "learning2")
print("param4 is : " .. param4)
print("param5 is : " .. param5)
-- return 也會將結果返回給 resume
return "coroutine return" , 1+2
end)
--第一次執行,將參數傳給input
print("first resume", wrap("coroutine function"))
print("this is main chunk")
--第二次執行,將參數作爲yield的返回值,傳給param1 param2 param3
print("second resume", wrap("param1", "param2", "param3"))
--第三次執行,將參數作爲yield的返回值,傳給param4 param5 多餘的param6被捨棄
print("third resume", wrap("param4", "param5", "param6"))
輸出:
注:coroutine.wrap不是保護模式運行,如果發生任何錯誤,拋出這個錯誤。如下
local wrap = coroutine.wrap(
function (input)
print("input : "..input)
local param1, param2 ,param3 = coroutine.yield("yield1", "learning1")
print("param1 is : " .. param1)
print("param2 is : " .. param2)
print("param3 is : " .. param3)
local param4 = coroutine.yield("yield2", "learning2")
print("param4 is : " .. param4)
print("param5 is : " .. param5)
-- return 也會將結果返回給 resume
return "coroutine return" , 1+2
end)
--第一次執行,將參數傳給input
print("first resume", wrap("coroutine function"))
print("this is main chunk")
--第二次執行,將參數作爲yield的返回值,傳給param1 param2 param3
print("second resume", wrap("param1", "param2", "param3"))
--第三次執行,將參數作爲yield的返回值,傳給param4 param5 多餘的param6被捨棄
print("third resume", wrap("param4", "param5", "param6"))
輸出:
5. coroutine.running()
返回當前的協程,如果實在主線程,則返回nil
local co = coroutine.create(
function ()
print(coroutine.running())
end)
print(coroutine.running())
coroutine.resume(co)
print(co)
輸出: