協同程式本質上是共同作業的,它允許兩種或多種方法以受控方式執行。 使用協同程式,在任何給定時間,只有一個協同程式執行,並且此執行協程僅在顯式請求暫停時暫停執行。
上述定義可能看起來含糊不清。 假設有兩種方法,一種是主程式方法,另一種是協程。 當使用resume
函式呼叫一個協程時,它會開始執行,當呼叫yield
函式時,它會暫停執行。 同樣的協同程式可以繼續執行另一個恢復函式呼叫,協同程式就會暫停。 該過程可以持續到協程執行結束。
下表列出了Lua中協程的所有可用函式及其相應的用法。
編號 | 方法 | 作用或目的 |
---|---|---|
1 | coroutine.create (f) |
使用函式f 建立一個新的協同程式,並返回thread 型別的物件。 |
2 | coroutine.resume (co [, val1, ...]) |
恢復協程co 並傳遞引數(如果有的話)。它返回操作狀態和可選的其他返回值。 |
3 | coroutine.running () |
如果在主執行緒中呼叫,則返回正在執行的協同程式或nil 。 |
4 | coroutine.status (co) |
根據協同程式的狀態返回running ,normal ,suspended 或dead 中的一個值。 |
5 | coroutine.wrap (f) |
與coroutine.create 一樣,coroutine.wrap 函式也會建立一個協同程式,但它不會返回協同程式本身,而是返回一個函式,當呼叫它時,它會恢復協同程式。 |
6 | coroutine.yield (...) |
暫停正在執行的協同程式。 傳遞給此方法的引數充當resume 函式的附加返回值。 |
範例
下面來看一個例子,通過此範例來理解協同程式的概念。
co = coroutine.create(function (value1,value2)
local tempvar3 = 10
print("coroutine section 1", value1, value2, tempvar3)
local tempvar1 = coroutine.yield(value1+1,value2+1)
tempvar3 = tempvar3 + value1
print("coroutine section 2",tempvar1 ,tempvar2, tempvar3)
local tempvar1, tempvar2= coroutine.yield(value1+value2, value1-value2)
tempvar3 = tempvar3 + value1
print("coroutine section 3",tempvar1,tempvar2, tempvar3)
return value2, "end"
end)
print("main", coroutine.resume(co, 3, 2))
print("main", coroutine.resume(co, 12,14))
print("main", coroutine.resume(co, 5, 6))
print("main", coroutine.resume(co, 10, 20))
當執行上面的程式時,將得到以下輸出 -
coroutine section 1 3 2 10
main true 4 3
coroutine section 2 12 nil 13
main true 5 1
coroutine section 3 5 6 16
main true 2 end
main false cannot resume dead coroutine
上面的例子是實現什麼功能?
如前所述,使用resume
函式來啟動操作和yield
函式來停止操作。 此外,可以看到coroutine
的恢復功能接收到多個返回值。
co
,協同程式將兩個變數作為引數。3
和2
保留在臨時變數value1
和value2
中,直到協程結束。tempvar3
,它最初值是10
,並且通過後續的協程呼叫更新為13
和16
,在整個協程的執行過程中value1
的值保持為3
。coroutine.yield
將兩個值4
和3
返回到resume
函式,通過更新yield
語句中的輸入引數為3
和2
。 它還接收協程執行的true/false
狀態。resume
呼叫的句子; 可以看到變數coroutine.yield
接收下一個呼叫引數,它提供了一種強大的方法,可以通過保留現有的引數值來進行新的操作。false
並且響應語句為:cannot resume dead coroutine。下面來看一個簡單的協同程式範例,它使用yield
函式和resume
函式返回1
到5
之間的數位。 如果不可用它會建立協程,或者恢復現有的協程。
function getNumber()
local function getNumberHelper()
co = coroutine.create(function ()
coroutine.yield(1)
coroutine.yield(2)
coroutine.yield(3)
coroutine.yield(4)
coroutine.yield(5)
end)
return co
end
if(numberHelper) then
status, number = coroutine.resume(numberHelper);
if coroutine.status(numberHelper) == "dead" then
numberHelper = getNumberHelper()
status, number = coroutine.resume(numberHelper);
end
return number
else
numberHelper = getNumberHelper()
status, number = coroutine.resume(numberHelper);
return number
end
end
for index = 1, 10 do
print(index, getNumber())
end
當執行上面的程式時,將得到以下輸出。
1 1
2 2
3 3
4 4
5 5
6 1
7 2
8 3
9 4
10 5
通常會將協同程式與多路程式設計語言的執行緒進行比較,但需要了解協同程式具有類似的執行緒功能,但協同程式一次只執行一個程式,並且永遠不會同時執行。
通過暫時保留某些資訊來控制程式執行順序以滿足需求。 使用帶有協同程式的全域性變數為協同程式提供了更大的靈活性。