Skip to content

Lua 的协同线程和协同函数

协同线程

Lua 中有一种特殊线程, 称为 coroutine, 协同线程, 简称协程;

coroutine 可以在运行时暂停执行, 然后转去执行其它线程; 也可以返回继续执行没有执行完毕的内容; 即可走可停再走;

协同线程也被称为协作多线程, 在 Lua 中表示独立的执行线程; 任意时刻只会有一个协程执行, 而不会出现多个协程同时执行的情况;

协同线程的类型为 thread , 启动、暂停、重启等, 均需要通过函数来控制; 常用函数如下表所示:

方法描述
create(function)创建一个协同线程实例,即返回的是thread类型。参数是一个function。其需要通过resume()来启动协同线程的执行
resume(thread,...)启动指定的协同线程的执行,使其从开始处或前面挂起处开始执行。可以向create()的内置函数传递相应的参数。如果内置函数具有返回值,resume()会全部接收并返回。
running()返回正在运行的协同线程实例,即thread类型值
yield()挂起协同线程,并将协同线程设置为挂起状态。resume()可从挂起处重启被挂起的协同线程
status(thread)查看协同线程的状态。状态有三种:运行态running,挂起态suspended,消亡态dead
close()关闭协同线程
wrap(function)创建一个协同函数,返回的是function类型。一旦调用该函数就会创建并执行一个协同线程实例

基本示例一: 内置执行函数没有返回值

lua
-- thread_create_test.lua

-- 创建一个协同线程实例
-- 接收参数 function
crt = coroutine.create(
    function (a, b)
        print(a, b, a + b);
        -- 获取正在运行的协同线程实例,thread类型
        local tr = coroutine.running();
        -- 输出获取的协同线程实例
        print(tr);
        print(type(tr)); -- 获取协同线程的类型
        print(coroutine.status(crt)); -- 查看协同线程的状态
        -- 将协同线程实例 挂起
        coroutine.yield();
        -- 挂起后 后续语句不会执行
        -- 当重新启动后 后续语句才会运行
        print("协同线程再次被启动!!!");
    end
)

-- 启动协同线程
coroutine.resume(crt, 3, 5); -- 函数返回值为内置函数返回值或启动线程的状态
-- 主线程查看协程类型
print("main-thread- " .. type(crt));
-- 在主线程查看线程实例的状态
print("main-thread- " .. coroutine.status(crt));

-- 继续启动协同线程 第二次启动可以不必再传参
coroutine.resume(crt);
-- 再次查看状态
print("main-thread- " .. type(crt));

执行结果如下:

基本示例二: 内置执行函数有返回值

lua
-- thread_create_test_2.lua

crt = coroutine.create(
    function (a, b)
        print(a, b);
        -- 将当前协程挂起 并携带两个返回值
        coroutine.yield(a * b, a / b);
        print("协程再次运行!!!");
        -- 返回两个值
        return a+b, a-b;
    end
);

-- 接收参数:启动状态-是否成功,返回值1,返回值2
local success, result_1, result_2 = coroutine.resume(crt, 12, 3);
print(success, result_1, result_2);

-- 继续执行
success, result_1, result_2 = coroutine.resume(crt, 12, 3);
print(success, result_1, result_2);

执行结果如下:

协同函数

协同线程可以单独创建执行, 也可以通过协同函数的调用启动执行;

使用 coroutine 的 wrap() 函数创建的就是协同函数, 类型为 function;

由于协同函数的本质就是函数, 所以协同函数的调用方式就是标准的函数调用方式; 只是, 协同函数的调用会启动内置的协同线程;

协同函数示例如下所示:

lua
-- thread_function_test.lua

-- 创建一个协同函数
cf = coroutine.wrap(
    function (a, b)
        print(a, b);

        -- 获取当前协同函数创建的协同线程
        local tr = coroutine.running();
        print("tr 的类型是: " .. type(tr));

        -- 挂起当前的协同线程
        coroutine.yield(a-b, a / b);

        print("协同线程再次启动!!!");

        return a+b, a*b;
    end
);
-- 调用协同函数
local r1, r2 = cf(3, 5);
print(type(cf)); -- 协同函数类型
print(r1, r2);

r1, r2 = cf(3, 5); -- 再次启动协同函数 此时的参数是可省略的
print(r1, r2);

-- 另一种重启协同线程方式
-- 将协同函数内的协同线程返回 并接收
-- 然后再次调用协同线程的 resume 方法