Lua协程-coroutine

lua也有协程这个机制,用以完成非抢占式的多任务处理。

协程与线程

协程和线程类似,有自己的堆栈、局部变量、指令指针等等。但同时也有不一致的地方,其中最重要的地方在于多线程程序可以同一时间运行多个线程,而协程同一时间只能运行一个,并且运行期间只有被显式要求挂起的时候才会选择挂起操作。

基础操作

coroutine.create(func)代表创建一个协程,也是个高级函数,参数即是function。

coroutine.status(co)查看当前协程状态,参数是协程本身,返回status string。

coroutine.resume(co)使协程由挂起态转为运行态,参数是协程本身,以及协程需要的参数。返回的是是否成功运行,如若不成功还会附加错误信息作为返回。

coroutine.yield()将当前协程挂起。

---@param f async fun(...):...
---@return thread
---@nodiscard
function coroutine.create(f) end

---@param co thread
---@return
---| '"running"'   # 正在运行。
---| '"suspended"' # 挂起或是还没有开始运行。
---| '"normal"'    # 是活动的,但并不在运行。
---| '"dead"'      # 运行完主体函数或因错误停止。
---@nodiscard
function coroutine.status(co) end

---@param co    thread
---@param val1? any
---@return boolean success
---@return any ...
function coroutine.resume(co, val1, ...) end

---@async
---@return any ...
function coroutine.yield(...) end

如下一段示例代码:

Lua 复制代码
co = coroutine.create(function ()
    for i = 1,3 do
        print("co", i)
        coroutine.yield()
    end
end)
print(coroutine.status(co))--suspended
coroutine.resume(co)--co      1
print(coroutine.status(co))--suspended
coroutine.resume(co)--co      2
coroutine.resume(co)--co      3
print(coroutine.status(co))--suspended
coroutine.resume(co)--
print(coroutine.status(co))--dead
print(coroutine.resume(co))--false   cannot resume dead coroutine

生产者-消费者

解决生产者消费者的问题就是如何能根据消费者请求数目的多少来决定生产者生产多少,此刻用协程再合适不过,比如官方文档的示例代码:

Lua 复制代码
function receive () 
    local status, value = coroutine.resume(producer) 
    return value 
end 
function send (x) 
    coroutine.yield(x) 
end 
producer = coroutine.create( function () 
    while true do
        local x = io.read() -- produce new value 
        send(x) 
    end 
end)

协程参数

当然我们可以试着修改这部分代码,改为传入一个数组,每次从中取出相应值:

Lua 复制代码
function receive(tb)
    local status, value = coroutine.resume(producer,tb)
    return value
end
producer = coroutine.create(function (tb)
    for i = 1,#tb do
        coroutine.yield(tb[i])
    end
end)

print(receive({1,2,3})) --1
print(receive({2,3,4})) --2
print(receive({5,6,7,8,9})) --3
print(receive({1,2,3,4})) --nil

发现了一个问题没有,只有第一次的数组赋值是正确的,之后的任意一次传参都是失败的。说明在第一次resume时就需要保证参数是正确的,而且后几次传参也只能在第一次传参的基础上继续执行,之后的参数并不能覆盖之前的参数。

如果这个tb是个全局变量,则是:

Lua 复制代码
function receive()
    local status, value = coroutine.resume(producer)
    return value
end

producer = coroutine.create(function ()
    for i = 1,#tb do
        coroutine.yield(tb[i])
    end
end)

tb = {1,2,3}
print(receive()) --1
tb = {2,3,4}
print(receive()) --3
tb = {4,5}
print(receive({5,6,7,8,9})) --nil
tb = {4,5,6,7}
print(receive({1,2,3,4})) --nil
相关推荐
Gu Gu Study5 分钟前
枚举与lambda表达式,枚举实现单例模式为什么是安全的,lambda表达式与函数式接口的小九九~
java·开发语言
时光の尘20 分钟前
C语言菜鸟入门·关键字·float以及double的用法
运维·服务器·c语言·开发语言·stm32·单片机·c
以后不吃煲仔饭34 分钟前
Java基础夯实——2.7 线程上下文切换
java·开发语言
进阶的架构师35 分钟前
2024年Java面试题及答案整理(1000+面试题附答案解析)
java·开发语言
前端拾光者39 分钟前
利用D3.js实现数据可视化的简单示例
开发语言·javascript·信息可视化
程序猿阿伟40 分钟前
《C++ 实现区块链:区块时间戳的存储与验证机制解析》
开发语言·c++·区块链
傻啦嘿哟1 小时前
如何使用 Python 开发一个简单的文本数据转换为 Excel 工具
开发语言·python·excel
大数据编程之光1 小时前
Flink Standalone集群模式安装部署全攻略
java·大数据·开发语言·面试·flink
初九之潜龙勿用1 小时前
C#校验画布签名图片是否为空白
开发语言·ui·c#·.net
Dola_Pan1 小时前
C语言:数组转换指针的时机
c语言·开发语言·算法