协同程序本质上是协作的,它允许两种或多种方法以受控方式执行。 使用协同程序,在任何给定时间,只有一个协同程序运行,并且此运行协程仅在显式请求暂停时暂停执行。
上述定义可能看起来含糊不清。 假设有两种方法,一种是主程序方法,另一种是协程。 当使用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
通常会将协同程序与多路程序设计语言的线程进行比较,但需要了解协同程序具有类似的线程功能,但协同程序一次只执行一个程序,并且永远不会同时执行。
通过暂时保留某些信息来控制程序执行顺序以满足需求。 使用带有协同程序的全局变量为协同程序提供了更大的灵活性。