一:协程与线程的区别

在 Lua 里,最主要的线程是协同程序(coroutine),它跟线程差不多,拥有自己独立的栈、局部变量和指令指针,可以跟其他协同程序共享全局变量和其他大部分东西
线程跟协程的区别:线程可以同时多个运行,而协程任意时刻只能运行一个,并且处于运行状态的协程只有被挂起(suspend)时才会暂停


二:什么是协程

协程和线程都是针对于函数来说的,一个函数的正常执行步骤是执行完此函数的所有代码再继续执行下面的代码
Lua(十五)——协同程序_热更新
但是协程可以让函数在某一步暂停(暂停也称为挂起),在挂起的地方先暂停函数去执行函数外的代码,然后在需要的时候让没有执行的代码继续执行
Lua(十五)——协同程序_热更新_02


三:定义协程

——coroutine.create() 
返回值为一个协程(函数)
Lua(十五)——协同程序_热更新_03

 


——coroutine.wrap() 
返回值为一个协程(函数)
Lua(十五)——协同程序_热更新_04

注意:
1.create后面必须跟上括号,括号不能放在下一行
2.协程必须定义为一个匿名函数

Lua(十五)——协同程序_Lua 热更新_05


四:开启协程

——coroutine.resume()
Lua(十五)——协同程序_Lua 热更新_06

 


——像调用函数一样
Lua(十五)——协同程序_热更新_07

使用coroutine.create和coroutine.wrap定义的区别:
使用create定义的协同程序在开启时需要使用coroutine.resume开启,而用wrap定义的协同程序在开启时只需要像调用函数一样开启
Lua(十五)——协同程序_热更新_08


五:暂停协程

coroutine.yield()
使程序暂停在coroutine.yield()的地方
Lua(十五)——协同程序_Lua 热更新_09


六:继续协程

继续协程的函数与开启协程的函数一样:
第一次执行时必须传入需要的参数,继续执行可以不传入参数,直接开启协程即可
Lua(十五)——协同程序_Lua 热更新_10


七:协同函数的返回值

——协同函数执行完成后有返回值 
匿名函数最终返回的值就是返回的参数,可以返回多个值
1.coroutine.resume的第一个返回值永远为是否开启协程成功,后面的值才是协同函数的返回值
2.像调用函数一样开启的返回值就是协同函数的返回值
Lua(十五)——协同程序_Lua 热更新_11

 


——协同函数暂停时有返回值 
coroutine.yield的参数就是暂停时返回的参数,可以返回多个值
1.coroutine.resume的第一个返回值永远为是否开启协程成功,后面的值才是协同函数的返回值
2.像调用函数一样开启的返回值就是协同函数的返回值
Lua(十五)——协同程序_热更新_12


八:查看协程的状态

coroutine.status()
只能用于coroutine.create创建的协同函数,返回一个当前状态的字符串
创建一个协程后它的默认状态就是suspended

在协同函数外面获取到的状态永远都不会是running只可能是dead或者suspended,因为当协程被挂起时或者执行完时才会执行协同函数外的代码
Lua(十五)——协同程序_Lua 热更新_13     
想要取得正在运行的状态需要在协同函数内部获取
Lua(十五)——协同程序_Lua 热更新_14

一个协同函数的生命周期:
Lua(十五)——协同程序_热更新_15


九:获取正在运行的线程号

coroutine.running()
返回值为协同函数的线程号(内存地址)
同样适用于coroutine.create和coroutine.wrap定义的协程

与获取协程状态一样如果在协同函数外面获取则永远都是nil
Lua(十五)——协同程序_Lua 热更新_16
想要取得正在运行的线程号需要在协同函数内部获取
Lua(十五)——协同程序_热更新_17


十:案例分析

——第一个

function yieldReturn(arg) return arg end

co_yieldtest = coroutine.create(
    function()
        print("启动协程状态"..coroutine.status(co_yieldtest))
        print("--")
        coroutine.yield()
        coroutine.yield(1)
        coroutine.yield(print("第3次调用"))
        coroutine.yield(yieldReturn("第4次调用"))
        return 2
    end
)

    print("启动前协程状态"..coroutine.status(co_yieldtest))
    print("--")

for i = 1,6 do
    print("第"..i.."次调用协程:", coroutine.resume(co_yieldtest))
    print("当前协程状态"..coroutine.status(co_yieldtest))
    print("--")
end

Lua(十五)——协同程序_热更新_18

 

 

 

——第二个

function foo (a)
    print("foo 函数输出", a)
    return coroutine.yield(2 * a) 
end
 
co = coroutine.create(function (a , b)
    print("第一次协同程序执行输出", a, b)
    local r = foo(a + 1)
     
    print("第二次协同程序执行输出", r)
    local r, s = coroutine.yield(a + b, a - b)
     
    print("第三次协同程序执行输出", r, s)
    return b, "结束协同程序"           
end)
        
print("main", coroutine.resume(co, 1, 10))
print("--分割线----")
print("main", coroutine.resume(co, "r"))
print("---分割线---")
print("main", coroutine.resume(co, "x", "y"))
print("---分割线---")
print("main", coroutine.resume(co, "x", "y"))
print("---分割线---")

Lua(十五)——协同程序_Lua 热更新_19

 

 

 

——第三个

local newProductor

function productor()
     local i = 0
     while true do
          i = i + 1
          send(i)     -- 将生产的物品发送给消费者
     end
end

function consumer()
     while true do
          local i = receive()     -- 从生产者那里得到物品
          print(i)
     end
end

function receive()
     local status, value = coroutine.resume(newProductor)
     return value
end

function send(x)
     coroutine.yield(x)     -- x表示需要发送的值,值返回以后,就挂起该协同程序
end

-- 启动程序
newProductor = coroutine.create(productor)
consumer()

Lua(十五)——协同程序_Lua 热更新_20