先来看看《Lua程序设计》中是如何讲解Lua协程的:
协同程序与多线程的线程比较类似:有自己的堆栈,自己的局部变量,有自己的指令指针,但是和其它协同程序共享全局变量等很多信息。线程和协同程序的主要不同在于:在多处理器情况下,从概念上讲多线程程序同时运行多个线程,而协同程序是通过协作来完成的,在任一指定时刻只有一个协同程序在运行,并且这个正在运行的协同程序只有在明确的被要求挂起的时候才会被挂起。
lua通过table提供了所有的协同函数,create函数创建一个新的协同程序,create只有一个参数;协同程序将要运行的代码封装成函数,返回值为thread类型的值表示创建了一个新的协同程序。协同有三个状态:挂起态(suspended)、运行态(running)、死亡(dead)。注意的是:lua提供的协同是一种不对称的协同,就是说挂起一个正在执行的协同的函数与使一个被挂起的协同再次执行的函数是不同的。
官方文档翻译:
Lua 支持 coroutine, 这个东西也被称为协同式多线程 (collaborative multithreading) 。Lua 为每个coroutine提供一个独立的运行线路。 然而和多线程系统中的线程不同,coroutine 只在显式的调用了 yield 函数时才会挂起。
创建一个 coroutine 需要调用一次 coroutine.create 。 它只接收单个参数,这个参数是 coroutine 的主函数。 create 函数仅仅创建一个新的 coroutine 然后返回它的控制器 (一个类型为 thread 的对象); 它并不会启动 coroutine 的运行。
当你第一次调用 coroutine.resume 时, 所需传入的第一个参数就是 coroutine.create 的返回值。 这时,coroutine 从主函数的第一行开始运行。 接下来传入 coroutine.resume 的参数将被传进 coroutine 的主函数。 在 coroutine 开始运行后,它讲运行到自身终止或是遇到一个 yields 。
coroutine 可以通过两种方式来终止运行: 一种是正常退出,指它的主函数返回(最后一条指令被运行后,无论有没有显式的返回指令); 另一种是非正常退出,它发生在未保护的错误发生的时候。 第一种情况中, coroutine.resume 返回 true , 接下来会跟着 coroutine 主函数的一系列返回值。 第二种发生错误的情况下, coroutine.resume 返回 false , 紧接着是一条错误信息。
coroutine 中切换出去,可以调用 coroutine.yield 。 当 coroutine 切出,与之配合的 coroutine.resume 就立即返回, 甚至在 yield 发生在内层的函数调用中也可以(就是说, 这不限于发生在主函数中,也可以是主函数直接或间接调用的某个函数里)。 在 yield 的情况下,coroutine.resume 也是返回 true, 紧跟着那些被传入 coroutine.yield 的参数。 等到下次你在继续同样的 coroutine ,将从调用 yield 的断点处运行下去。 断点处 yield 的返回值将是 coroutine.resume 传入的参数。
类似 coroutine.create,coroutine.wrap 这个函数也将创建一个 coroutine , 但是它并不返回 coroutine 本身,而是返回一个函数取而代之。一旦你调用这个返回函数,就会切入 coroutine 运行。 所有传入这个函数的参数等同于传入 coroutine.resume 的参数。 coroutine.wrap 会返回所有应该由除第一个(错误代码的那个布尔量) 之外的由 coroutine.resume 返回的值。 和 coroutine.resume 不同, coroutine.wrap 不捕获任何错误; 所有的错误都应该由调用者自己传递。
Code:
function foo (a)
print("foo", a)
return coroutine.yield(2 * a)
end
co = coroutine.create(function (a, b)
print("co-body", a, b)
local r = foo(a+1)
print("co-body", r)
local r, s = coroutine.yield(a+b, a-b)
print("co-body", r, s)
return b, "end"
end)
print("main", coroutine.resume(co, 1, 10))
print("main", coroutine.resume(co, "r"))
print("main", coroutine.resume(co, "x", "y"))
print("main", coroutine.resume(co, "x", "y"))
Output:
co-body 1 10
foo 2
main true 4
co-body r
main true 11 -9
co-body x y
main true 10 end
main false cannot resume dead coroutine