协程(Coroutine)
协程 可以颠倒调用者和被调用者的关系,而且这种灵活性解决了软件架构中的被称为“谁是老大(who-is-the-boss)” 或者“谁拥有主循环(who-has-the-main-loop)”的问题。 这是对诸如事件驱动编程\通过构造器构建迭代器和协作式多线程等几个表面不相关的问题的泛化,而协程以简单有效的方式解决了问题。
从多线程角度来看,协程和线程类似:协程是一系列的可执行语句,拥有自己的栈、局部变量和指令指针,同时协程又与其他协程共享了全局变量和其他几乎一切资源。线程与协程的主要区别在于,一个多线程程序可以并行运行多个线程,而协程却要彼此协作地运行,即在任意实可只能有一个协程运行,且只有当正在运行的协程要求被挂起时其执行才会暂停。
协程基础
Lua 语言中协程有关的所有函数被放在表 coroutine 中。函数 create 用于创建新协程,该函数只有一个参数,即协程要执行的代码的函数(协程体(body))。 函数 create 返回一个 “thread"类型的值,即新协程。
co = coroutine.create(function () print("hi") end)
print(type(co)) -->thread
一个协程有四种状态,即挂起(suspended)、 运行、正常和死亡。通过 coroutine.status 函数可以检查协程的状态。
当一个协程被创建时,它处于挂起状态,即协程不会再被创建时自动执行。函数 coroutine.resume 用于启动或再次启动一个写成的执行,并将其状态由挂起改为运行:
coroutine.resume(co) -->hi
协程的真正强大之处在于函数 yield , 该函数可以让一个运行中的协程挂起自己,然后在后续恢复运行。
co = coroutine.create(function ()
for i = 1, 10 do
print("co", i)
coroutine.yield()
end
end)
协程进行了一个循环,在循环中输出数字在每次打印后挂起。当唤醒协程后,它就会开始执行知道遇到第一个 yield:
coroutine.yield() -->co 1
此处,如果我们查看协程状态,会发现协程处于挂起状态,因此可以再次恢复运行:
print(coroutine.status(co)) -->suspended
从协程的角度看,在挂起期间发生的活动都发生在协程调用 yield 期间。当我们唤醒协程时,函数 yield才会最终返回,然后协程会继续执行知道遇到下一个yield或执行结束
coroutine.resume(co) -->co 2
coroutine.resume(co) -->co 3
...
coroutine,resume(co) -->co 10
coroutine.resume(co) -->no data
最后一次调用resume时,协程体执行完毕并返回,不输出任何数据。