Lua 基础教程(十六)协程
hudson 译 原文
简单介绍
协程本质上是协作的,允许两种或多种方法以受控的方式执行。 使用多个协程合作时,任何给定时间只运行一个协程,并且只有在明确请求时才会暂停执行。
上面的定义看起来很模糊。假设有两种方法:主程序方法和协程。 当使用“resume”函数调用协程时,它开始执行,调用“yield”函数时,它会暂停执行。 通过再次调用“resume”函数,同一协程可以从暂停的地方恢复执行。 这个过程可以持续到协程的执行完成。
协程有哪些功能?
下表列出了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,但返回一个函数,调用该函数会恢复协程的执行。 |
| 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”函数停止协程。此外,协程的“resume”函数接收多个返回值。
-
首先创建一个协程,它有两个参数,将其赋值给变量
co。 -
在调用第一个“resume”函数时,值
3和2保留在临时变量中,直到协程结束。 -
为了理解这一点,我们使用了tempvar3,最初是
10,它通过协程的后续调用更新为13和16,因为在协程的整个执行过程中,value1一直保持为3 -
第一个“coroutine.yield”返回两个值(4和3)到“resume”函数。它还接收协程执行的状态(真/假)。
-
关于协程的另一件事是,在上述示例中,
resume调用的下一个参数是如何处理的;你可以看到,“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
值得注意的是,虽然协程在多编程语言中与线程共享一些功能,但它们一次执行一个,而且永远不会同时执行。使用协程,可以控制程序执行序列并暂时保留信息。在使用全局变量时协程可提供更大的灵活性。