Lua协程

Lua 协同程序(coroutine)与线程比较类似:拥有独立的堆栈,独立的局部变量,独立的指令指针,同时又与其它协同程序共享全局变量和其它大部分东西。

协同是非常强大的功能,但是用起来也很复杂。

协程与线程区别

协程类似一种多线程,但与多线程还有很多区别:

  1. 协程并非 os 线程,所以创建、切换开销比线程相对要小。
  2. 协程与线程一样有自己的栈、局部变量等,但是协程的栈是在用户进程空间模拟的,所以创建、切换开销很小。
  3. 多线程程序是多个线程并发执行,也就是说在一瞬间有多个控制流在执行。而协程强调的是一种多个协程间协作的关系,只有当一个协程主动放弃执行权,另一个协程才能获得执行权,所以在某一瞬间,多个协程间只有一个在运行。
  4. 由于多个协程时只有一个在运行,所以对于临界区的访问不需要加锁,而多线程的情况则必须加锁。
  5. 多线程程序由于有多个控制流,所以程序的行为不可控,而多个协程的执行是由开发者定义的所以是可控的。

Lua 的协程是不对称的(asymmetric coroutines),是指 “挂起一个正在执行的协同函数” 和 “使一个被挂起的协程再次执行的函数” 是不同的。

有些语言使用对称协同(symmetric coroutines),即使用同一个函数负责 “执行与挂起间的状态切换”。

基本语法

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

协程状态

状态 说明
suspended 挂起状态,协程刚创建完成时或者 yield 之后
running 运行状态,如果在协程的函数中调用 status,传入协程自身的句柄,那么执行到这里的时候才会返回 running 状态
normal 如果协程 A resume() 协程 B 时,则协程 A 处于的状态为 normal。在协程 B 的执行过程中,协程 A 就一直处于 normal 状态。因为它这时候既不是挂起状态、也不是运行状态
dead 结束状态,如果一个协程发生错误结束或正常运行结束。那么就处于 dead 状态,这时候如果调用 resume() 的话会直接返回 false,且报错 “cannot resume dead coroutine”

Lua协程总结

Lua 协同程序(coroutine)与线程比较类似:拥有独立的堆栈,独立的局部变量,独立的指令指针,同时又与其它协同程序共享全局变量和其它大部分东西。