Lua 协同程序的理解

一、什么协同程序

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

二、协同程序和线程的区别

       线程与协同程序的主要区别在于,一个具有多个线程的程序可以同时运行几个线程,而协同程序却需要彼此协作的运行。在任一指定时刻只有一个协同程序在运行,并且这个正在运行的协同程序只有在明确的被要求挂起的时候才会被挂起。协同程序有点类似同步的多线程,在等待同一个线程锁的几个线程有点类似协同。

三、协同函数的生命周期

       协同函数的生命周期为:dead,suspend,running。协同函数被创建完成后,进入suspend状态。通过coroutine.resume()函数启动,进入running状态,然后,在通过coroutine.yield()函数,再次进入suspend状态,直到该协同函数执行完毕后,进入dead状态;一旦进入dead状态,该协同函数,无法再通过coroutine.resume()函数进入running状态

四、协同函数的resume和yield方法的理解

       对于这两个方法,单独使用和理解起来并不困难。初学比较难以理解的是,二者的结合使用情景的理解。下面我将引用菜鸟教程上的一个例子来加深这方面的理解。
       首先,要注意一个概念,即:coroutine.resume()函数的参数会作为coroutine.yield()函数的返回值,coroutine.yield()函数的参数,会作为coroutine.resume()函数的返回值。二者是对应的关系。具体示例如下:

--前提条件
--注意,第一个yiled的参数,作为第一个resume函数的返回值。
--第二个resume函数的参数,第二个参数作为第一个yiled的返回值。
function foo (a)
    print("foo 函数输出", a)
    --第一个yield
    return coroutine.yield(2 * a) -- 返回  2*a 的值
end
--创建一个协同函数
co = coroutine.create(function (a , b)
    print("第一次协同程序执行输出", a, b) -- co-body 1 10

    --此时,当前r的值本来为第一个yield返回的4,但由于第二个resume的参数为“r” 因此,此时r的值被更新为“r”.
    local r = foo(a + 1)

    print("第二次协同程序执行输出", r)
    --第二个yield
    local r, s = coroutine.yield(a + b, a - b)  -- a,b的值为第一次调用协同程序时传入

    --同理,当前r,s的值本来为第二个yield返回的11和-9,但由于第三个resume的参数为“x”,"y" 因此,此时r,s的值被更新为“x”,"y" .
    print("第三次协同程序执行输出", r, s)
    return b, "结束协同程序"                   -- b的值为第二次调用协同程序时传入
end)

--第一个resume
print("main", coroutine.resume(co, 1, 10)) -- true, 4
print("--分割线----")
--第二个resume
print("main", coroutine.resume(co, "r")) -- true 11 -9
print("---分割线---")
--第三个resume
print("main", coroutine.resume(co, "x", "y")) -- true 10 end
print("---分割线---")
--当上述协同函数执行完之后,该co协同函数已经进入了dead状态,因此,下面的第四个resume无法执行,
--所以,上面的第3个resume的返回值为协同函数执行完毕后返回b的值,即为10.
--第四个resume
print("main", coroutine.resume(co, "x", "y")) -- cannot resume dead coroutine
print("---分割线---")


--上述代码的输出信息:
--[[
第一次协同程序执行输出 1   10
foo 函数输出    2
main    true    4
--分割线----
第二次协同程序执行输出 r
main    true    11  -9
---分割线---
第三次协同程序执行输出 x   y
main    true    10  结束协同程序
---分割线---
main    false   cannot resume dead coroutine
---分割线---
--]]

上述代码的交互过程,可以参考下图来进行更好的理解:

这里写图片描述

       因此,我们可以利用这个特点, 实现全局数据与协同函数的数据的交互。resume和yield的配合强大之处在于,resume处于主程中,它将外部状态(数据)传入到协同程序内部;而yield则将内部的状态(数据)返回到主程中。

参考链接:http://www.runoob.com/lua/lua-coroutine.html

猜你喜欢

转载自blog.csdn.net/qq_24642743/article/details/80686907
今日推荐