教程 > Lua 教程 > Lua 基础 阅读:70

Lua 协程 Coroutine

介绍

协程本质上是协作的,它允许两个或多个方法以受控方式执行。 对于协程,在任何给定时间,只有一个协程运行,并且这个正在运行的协程只有在明确请求暂停时才会暂停其执行。

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


协程中可用的函数

下表列出了 Lua 中协程的所有可用函数及其对应的使用。

序号 方法 描述
1 coroutine.create() 创建 coroutine,返回 coroutine, 参数是一个函数,当和 resume 配合使用的时候就唤醒函数调用
2 coroutine.resume() 重启 coroutine,和 create 配合使用
3 coroutine.yield() 挂起 coroutine,将 coroutine 设置为挂起状态,这个和 resume 配合使用能有很多有用的效果
4 coroutine.status() 查看 coroutine 的状态
注:coroutine 的状态有三种:dead,suspended,running,具体什么时候有这样的状态请参考下面的程序
5 coroutine.wrap() 创建 coroutine,返回一个函数,一旦你调用这个函数,就进入 coroutine,和 create 功能重复
6 coroutine.running() 返回正在跑的 coroutine,一个 coroutine 就是一个线程,当使用running的时候,就是返回一个 corouting 的线程号

示例

让我们看一个例子来理解协程的概念。

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 和“无法恢复死协程”语句作为响应。

另一个协程示例

让我们看一个简单的协程,它在 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

协程经常与多道程序语言的线程进行比较,但我们需要了解协程具有线程的相似特性,但它们一次只执行一个,并且从不并发执行。

我们通过提供临时保留某些信息来控制程序执行顺序以满足需要。 在协程中使用全局变量为协程提供了更大的灵活性。

查看笔记

扫码一下
查看教程更方便