Lua - Coroutines

简介

协程本质上是协作的,它允许两种或多种方法以受控方式执行.使用协同程序,在任何给定时间,只有一个协同程序运行,并且此运行协程仅在明确请求暂停时暂停其执行.

上述定义可能看起来模糊.我们假设我们有两种方法,一种是主程序方法,另一种是协程.当我们使用resume函数调用一个协同程序时,它会开始执行,当我们调用yield函数时,它会暂停执行.同样的协程可以继续执行另一个恢复函数调用,从它被暂停.这个过程可以持续到协程执行结束.

协同程序中可用的函数

下表列出了协同程序中所有可用的函数Lua及其相应的用法.

Sr .No.方法&目的
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函数来停止操作.此外,您可以看到协程的恢复功能接收到多个返回值.

  • 首先,我们创建一个协同程序并将其分配给变量名称co,协程将两个变量作为参数.

  • 当我们调用第一个恢复函数时,值为3和2保留在临时变量value1和value2中直到协程结束.

  • 为了让您理解这一点,我们使用了tempvar3,最初为10由于在协程执行过程中value1保持为3,它会被协程的后续调用更新为13和16.

  • 第一个协同程序. yield返回两个值4和3到resume函数,我们通过更新yield语句中的输入参数3和2得到.它还接收协程执行的真/假状态.

  • 关于协同程序的另一个问题是如何处理下一个简历调用的句子,在上面例;你可以看到变量coroutine.yield接收下一个调用params,它提供了一种强大的方法来完成新操作并保留现有的param值.

  • 最后,一旦协程中的所有语句都被执行,后续调用将返回false并且"无法恢复死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

通常会将协同程序与多道程序设计语言的线程进行比较,但我们需要了解协同程序具有类似的线程特性,但它们一次只执行一个并且永远不会同时执行.

我们控制程序执行顺序以满足临时保留某些信息的需要.使用带有协同程序的全局变量为协同程序提供了更大的灵活性.