Lua 基础教程(十六)协程

92 阅读3分钟

Lua 基础教程(十六)协程

hudson 译 原文

简单介绍

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

上面的定义看起来很模糊。假设有两种方法:主程序方法和协程。 当使用“resume”函数调用协程时,它开始执行,调用“yield”函数时,它会暂停执行。 通过再次调用“resume”函数,同一协程可以从暂停的地方恢复执行。 这个过程可以持续到协程的执行完成。

协程有哪些功能?

下表列出了Lua中协程的所有可用功能及其用途:

序号方法用途
1coroutine.create (f)创建一个带有函数 f 的新协同程序,并返回一个类型为 "thread" 的对象。
2coroutine.resume (co [, val1, ...])恢复协程co 的执行,并传递参数(如果有)。返回操作状态和可选的其他返回值。
3coroutine.running ()返回正在运行的协程,如果是主线程,则返回 nil
4coroutine.status (co)返回协程的状态。 状态是以下值之一:running、normal、suspended 或 dead。
5coroutine.wrap (f)类似于 coroutine.create,但返回一个函数,调用该函数会恢复协程的执行。
6coroutine.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”函数时,值32保留在临时变量中,直到协程结束。

  • 为了理解这一点,我们使用了tempvar3,最初是10,它通过协程的后续调用更新为1316,因为在协程的整个执行过程中,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

值得注意的是,虽然协程在多编程语言中与线程共享一些功能,但它们一次执行一个,而且永远不会同时执行。使用协程,可以控制程序执行序列并暂时保留信息。在使用全局变量时协程可提供更大的灵活性。