Lua的协程,coroutine

--------------------------------------------------------------------------------
-- 不携带参数
--------------------------------------------------------------------------------
local main = function()
    print("step1")
    coroutine.yield()
    print("step2")
end
local co = coroutine.create(main)
coroutine.resume(co)
coroutine.resume(co)
-- 输出
step1 step2

以上是最简单的协程演示了

讲解:

1.coroutine.create创建一个协程

2.第一次coroutine.create运行到main函数的coroutine.yield()函数处停止

3.再次运行coroutine.create然后继续在main函数中断处运行,即运行main函数的第二个print

协程的参数稍微麻烦一些,最好能讲下面的详解看完,就能明白了,这里先上个最简单的演示参数传递的例子

--------------------------------------------------------------------------------
-- 携带参数传递
--------------------------------------------------------------------------------
local main = function(arg1)
    print (arg1)
    print (coroutine.yield("yield"))
    print (arg1)
end
local co = coroutine.create(main)
print(coroutine.resume(co, "resume1"))
print(coroutine.resume(co, "resume2"))  
-- ouput:
resume1
true    yield
resume2
resume1
true

对于协程的详解


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.createcoroutine.wrap 这个函数也将创建一个 coroutine , 但是它并不返回 coroutine 本身,而是返回一个函数取而代之。一旦你调用这个返回函数,就会切入 coroutine 运行。 所有传入这个函数的参数等同于传入 coroutine.resume 的参数。 coroutine.wrap 会返回所有应该由除第一个(错误代码的那个布尔量) 之外的由 coroutine.resume 返回的值。 和 coroutine.resume 不同, coroutine.wrap 不捕获任何错误; 所有的错误都应该由调用者自己传递。

Lua语言实现的协程是一种非对称式(asymmetric)协程,或称半对称式(semi-symmetric)协程,又或干脆就叫半协程(semi-coroutine)。

这种协程机制之所以被称为非对称的,是因为它提供了两种传递程序控制权的操作:

  • 一种是(重)调用协程(通过coroutine.resume);
  • 另一种是挂起协程并将程序控制权返回给协程的调用者(coroutine.yield)。

一个非对称协程可以看做是从属于它的调用者的,二者的关系非常类似于例程(routine)与其调用者之间的关系。既然有非对称式协程,当然也就有对称式(symmetric)协程了,它的特点是只有一种传递程序控制权的操作,即将控制权直接传递给指定的协程。曾经有这么一种说法,对称式和非对称式协程机制的能力并不等价,但事实上很容易根据前者来实现后者。

coroutine.create (f)

Creates a new coroutine, with body f. f must be a Lua function. Returns this new coroutine, an object with type "thread".


coroutine.resume (co [, val1, ···])

Starts or continues the execution of coroutine co. The first time you resume a coroutine, it starts running its body. The values val1, ··· are passed as the arguments to the body function. If the coroutine has yielded, resume restarts it; the values val1, ··· are passed as the results from the yield.

If the coroutine runs without any errors, resume returns true plus any values passed to yield (if the coroutine yields) or any values returned by the body function (if the coroutine terminates). If there is any error, resume returns false plus the error message.


coroutine.running ()

Returns the running coroutine, or nil when called by the main thread.


coroutine.status (co)

Returns the status of coroutine co, as a string: "running", if the coroutine is running (that is, it called status); "suspended", if the coroutine is suspended in a call to yield, or if it has not started running yet; "normal" if the coroutine is active but not running (that is, it has resumed another coroutine); and "dead" if the coroutine has finished its body function, or if it has stopped with an error.


coroutine.yield (···)

Suspends the execution of the calling coroutine. The coroutine cannot be running a C function, a metamethod, or an iterator. Any arguments to yield are passed as extra results to resume.


coroutine.wrap (f)

Creates a new coroutine, with body f. f must be a Lua function. Returns a function that resumes the coroutine each time it is called. Any arguments passed to the function behave as the extra arguments to resume. Returns the same values returned by resume, except the first boolean. In case of error, propagates the error.