Lua - 协程
协程介绍
协程(又称协同程序)本质上是协作的,它允许两个或多个方法以受控方式执行。 对于协程,在任何给定时间,只有一个协程运行,并且这个正在运行的协程只有在明确请求暂停时才会暂停其执行。
上面的定义可能看起来很模糊。 假设我们有两种方法,一种是主程序方法,一种是协程。 当我们使用 resume 函数调用协程时,它开始执行,当我们调用 yield 函数时,它暂停执行。 同样,同一个协程可以继续执行另一个暂停它的恢复函数调用。 这个过程可以一直持续到协程执行结束。
协程中可用的函数
下表列出了Lua中协程的所有可用函数及其对应的使用。
序号 | 方法 & 用途 |
---|---|
1 | coroutine.create (f) 使用函数 f 创建一个新的协程并返回一个"thread"线程类型的对象。 |
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 (...) 暂停正在运行的协程。 传递给此方法的参数充当恢复函数的附加返回值。 |
示例
让我们看一个例子来理解协程的概念。
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,并且在协程的后续调用中更新为 13 和 16,因为在协程执行期间 value1 保持为 3。
第一个 coroutine.yield 将两个值 4 和 3 返回到 resume 函数,我们通过更新 yield 语句中的输入参数 3 和 2 得到。 它还接收协程执行的真/假状态。
关于协程的另一件事是如何处理 resume call 的下一个参数,在上面的示例中; 您可以看到变量 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
常有人将协程与多道程序语言的线程进行比较,但我们需要了解协程具有线程的相似特性,但它们一次只执行一个,并且从不并发执行。
我们通过提供临时保留某些信息来控制程序执行顺序以满足需要。 在协程中使用全局变量为协程提供了更大的灵活性。