Lua - 协程
介绍
协程本质上是协作的,它允许两个或多个方法以受控方式执行。对于协程,在任何给定时间,只有一个协程运行,并且该正在运行的协程仅在明确请求挂起时挂起其执行。
上面的定义可能看起来很模糊。假设我们有两种方法,一种是主程序方法,另一种是协程。当我们使用resume函数调用协程时,它开始执行,当我们调用yield函数时,它暂停执行。同样,同一个协程可以从暂停的地方继续执行另一个恢复函数调用。这个过程可以一直持续到协程执行结束。
协程中可用的函数
下表列出了 Lua 中协程的所有可用函数及其相应的用途。
| 先生。 | 方法与目的 |
|---|---|
| 1 | 协程.create (f) 使用函数 f 创建一个新的协程并返回一个“thread”类型的对象。 |
| 2 | coroutine.resume (co [, val1, ...]) 恢复协程 co 并传递参数(如果有)。它返回操作的状态和可选的其他返回值。 |
| 3 | 协程.running() 返回正在运行的协程,如果在主线程中调用则返回 nil。 |
| 4 | 协程.status (co) 根据协程的状态返回运行、正常、挂起或死亡的值之一。 |
| 5 | 协程.wrap (f) 与 coroutine.create 一样,coroutine.wrap 函数也创建一个协程,但它不是返回协程本身,而是返回一个函数,该函数在调用时将恢复该协程。 |
| 6 | 协程.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得到的。它还接收协程执行的真/假状态。
关于协程的另一件事是如何处理恢复调用的下一个参数,在上面的示例中;您可以看到变量 coroutine.yield 接收下一个调用参数,这提供了一种在保留现有参数值的情况下执行新操作的强大方法。
最后,一旦协程中的所有语句都被执行,后续调用将返回 false 并响应“无法恢复死亡协程”语句。
另一个协程示例
让我们看一个简单的协程,它在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
人们经常将协程与多编程语言的线程进行比较,但我们需要了解,协程具有与线程类似的功能,但它们一次只执行一个,并且从不并发执行。
我们通过暂时保留某些信息来控制程序的执行顺序以满足需要。在协程中使用全局变量可以为协程提供更大的灵活性。