Lua協程



簡介

協程本質上是協作式的,它允許以受控的方式執行兩種或多種方法。使用協程時,在任何給定時間,只有一個協程執行,並且此執行的協程僅在其顯式請求暫停時才會暫停其執行。

上述定義可能看起來含糊不清。讓我們假設我們有兩個方法,一個是主程式方法,另一個是協程。當我們使用 resume 函式呼叫協程時,它開始執行;當我們呼叫 yield 函式時,它暫停執行。同一個協程可以使用另一個 resume 函式呼叫從暫停的地方繼續執行。這個過程可以持續到協程執行結束。

協程中可用的函式

下表列出了 Lua 中所有可用的協程函式及其對應的用途。

序號 方法及用途
1

coroutine.create (f)

使用函式 f 建立一個新的協程,並返回一個“執行緒”型別的物件。

2

coroutine.resume (co [, val1, ...])

恢復協程 co 並傳遞引數(如有)。它返回操作狀態和可選的其他返回值。

3

coroutine.running ()

返回正在執行的協程,如果在主執行緒中呼叫則返回 nil。

4

coroutine.status (co)

根據協程的狀態返回執行中、正常、暫停或死亡等值之一。

5

coroutine.wrap (f)

coroutine.create 類似,coroutine.wrap 函式也建立一個協程,但它不是返回協程本身,而是返回一個函式,當呼叫該函式時,會恢復協程。

6

coroutine.yield (...)

暫停正在執行的協程。傳遞給此方法的引數作為 resume 函式的附加返回值。

示例

讓我們來看一個例子來理解協程的概念。

main.lua

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 函式停止操作。此外,您可以看到協程的 resume 函式接收多個返回值。

  • 首先,我們建立一個協程並將其賦值給變數名 co,協程接收兩個變數作為引數。

  • 當我們呼叫第一個 resume 函式時,值 3 和 2 保留在臨時變數 value1 和 value2 中,直到協程結束。

  • 為了讓您理解這一點,我們使用了 tempvar3,它最初為 10,並且由於 value1 在協程執行過程中始終保持為 3,因此它通過後續的協程呼叫更新為 13 和 16。

  • 第一個 coroutine.yield 將兩個值 4 和 3 返回給 resume 函式,我們透過更新 yield 語句中的輸入引數 3 和 2 來獲得這些值。它還接收協程執行的真/假狀態。

  • 關於協程的另一件事是如何處理 resume 呼叫的下一個引數,在上面的例子中;您可以看到變數 coroutine.yield 接收下一個呼叫的引數,這提供了一種強大的方法來使用現有引數值的關係執行新操作。

  • 最後,一旦協程中的所有語句都執行完畢,後續呼叫將返回 false 和“無法恢復已死亡的協程”語句作為響應。

另一個協程示例

讓我們來看一個簡單的協程,它使用 yield 函式和 resume 函式返回 1 到 5 的數字。如果協程不存在,則建立協程;否則恢復現有的協程。

main.lua

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

協程經常與多程式語言的執行緒進行比較,但我們需要理解的是,協程具有與執行緒類似的功能,但它們一次只執行一個,永遠不會併發執行。

我們控制程式執行順序以滿足需求,並臨時保留某些資訊。在協程中使用全域性變數為協程提供了更大的靈活性。

廣告
© . All rights reserved.