Lua中的协同程序 coroutine

2023-11-12

int running = 1;


int lua_finish(lua_State * L) {
running = 0;
printf("lua_finish called\n");
return 0;
}
int lua_sleep(lua_State *L) {
printf("lua_sleep called\n");
//lua_pushnumber(L, 10);
return lua_yield(L, 0);
}


int main() {
lua_State* L = luaL_newstate();
luaL_openlibs(L);


lua_register(L, "sleep", lua_sleep);
lua_register(L, "finish", lua_finish);


//luaL_dofile(L, "scripts/init.lua");


lua_State* cL = lua_newthread(L);
luaL_loadfile(cL, "loop.lua");


while (running) {
int status;
lua_pushnumber(cL, 20);
status = lua_resume(cL, 1);
if (status == LUA_YIELD) {
printf("loop yielding\n");
}
else {
running = 0; // you can't try to resume if it didn't yield
// catch any errors below
if (status == LUA_ERRRUN && lua_isstring(cL, -1)) {
printf("isstring: %s\n", lua_tostring(cL, -1));
lua_pop(cL, -1);
}
}
}


//luaL_dofile(L, "scripts/end.lua");
lua_close(L);
return 0;

}


lua file


print("loop.lua")


local i = 0
while true do
    print("lua_loop iteration")
    local bret = sleep()
print(bret)


    i = i + 1
    if i == 4 then
        break
    end
end


finish()


 Lua中的协程和多线程很相似,每一个协程有自己的堆栈,自己的局部变量,可以通过yield-resume实现在协程间的切换。不同之处是:Lua协程是非抢占式的多线程,必须手动在不同的协程间切换,且同一时刻只能有一个协程在运行。并且Lua中的协程无法在外部将其停止,而且有可能导致程序阻塞。

 

协同程序(Coroutine):

  三个状态:suspended(挂起,协同刚创建完成时或者yield之后)、running(运行)、dead(函数走完后的状态,这时候不能再重新resume)。

  coroutine.create(arg):根据一个函数创建一个协同程序,参数为一个函数

  coroutine.resume(co):使协同从挂起变为运行(1)激活coroutine,也就是让协程函数开始运行;(2)唤醒yield,使挂起的协同接着上次的地方继续运行。该函数可以传入参数

  coroutine.status(co):查看协同状态

  coroutine.yield():使正在运行的协同挂起,可以传入参数

  resume函数的两种用途虽然都是使协同挂起,但还是有些许差异的,看下面这个例子:

coroutineFunc = function (a, b) 
    for i = 1, 10 do
        print(i, a, b)
        coroutine.yield()
    end
end

co2 = coroutine.create(coroutineFunc)        --创建协同程序co2
coroutine.resume(co2, 100, 200)                -- 1 100 200 开启协同,传入参数用于初始化
coroutine.resume(co2)                        -- 2 100 200 
coroutine.resume(co2, 500, 600)                -- 3 100 200 继续协同,传入参数无效

co3 = coroutine.create(coroutineFunc)        --创建协同程序co3
coroutine.resume(co3, 300, 400)                -- 1 300 400 开启协同,传入参数用于初始化
coroutine.resume(co3)                        -- 2 300 400 
coroutine.resume(co3)                        -- 3 300 400 

   Lua中协同的强大能力,还在于通过resume-yield来交换数据:

  (1)resume把参数传给程序(相当于函数的参数调用);

  (2)数据由yield传递给resume;

  (3)resume的参数传递给yield;

  (4)协同代码结束时的返回值,也会传给resume

   协同中的参数传递形势很灵活,一定要注意区分,在启动coroutine的时候,resume的参数是传给主程序的;在唤醒yield的时候,参数是传递给yield的。看下面这个例子:

co = coroutine.create(function (a, b) print("co", a, b, coroutine.yield()) end)
coroutine.resume(co, 1, 2)        --没输出结果,注意两个数字参数是传递给函数的
coroutine.resume(co, 3, 4, 5)        --co 1 2 3 4 5,这里的两个数字参数由resume传递给yield 

  Lua的协同称为不对称协同(asymmetric coroutines),指“挂起一个正在执行的协同函数”与“使一个被挂起的协同再次执行的函数”是不同的,有些语言提供对称协同(symmetric coroutines),即使用同一个函数负责“执行与挂起间的状态切换”。

   注意:resume运行在保护模式下,因此,如果协同程序内部存在错误,Lua并不会抛出错误,而是将错误返回给resume函数。

   以下是我个人的一点理解:

  (1)resume可以理解为函数调用,并且可以传入参数,激活协同时,参数是传给程序的,唤醒yield时,参数是传递给yield的;

  (2)yield就相当于是一个特殊的return语句,只是它只是暂时性的返回(挂起),并且yield可以像return一样带有返回参数,这些参数是传递给resume的。

为了理解上面两句话的含义,我们来看一下如何利用Coroutine来解决生产者——消费者问题的简单实现:

produceFunc = function()
    while true do
        local value = io.read()
        print("produce: ", value)
        coroutine.yield(value)        --返回生产的值
    end
end

consumer = function(p)
    while true do
        local status, value = coroutine.resume(p);        --唤醒生产者进行生产
        print("consume: ", value)
    end
end

--消费者驱动的设计,也就是消费者需要产品时找生产者请求,生产者完成生产后提供给消费者
producer = coroutine.create(produceFunc)
consumer(producer)

这是一种消费者驱动的设计,我们可以看到resume操作的结果是等待一个yield的返回,这很像普通的函数调用,有木有。我们还可以在生产消费环节之间加入一个中间处理的环节(过滤器):

produceFunc = function()
    while true do
        local value = io.read()
        print("produce: ", value)
        coroutine.yield(value)        --返回生产的值
    end
end

filteFunc = function(p)
    while true do
        local status, value = coroutine.resume(p);
        value = value *100            --放大一百倍
        coroutine.yield(value)
    end
end

consumer = function(f, p)
    while true do
        local status, value = coroutine.resume(f, p);        --唤醒生产者进行生产
        print("consume: ", value)
    end
end

--消费者驱动的设计,也就是消费者需要产品时找生产者请求,生产者完成生产后提供给消费者
producer = coroutine.create(produceFunc)
filter = coroutine.create(filteFunc)
consumer(filter, producer)

  可以看到,我们在中间过滤器中将生产出的值放大了一百倍。

  通过这个例子应该很容易理解coroutine中如何利用resume-yield调用来进行值传递了,他们像“调用函数——返回值”一样的工作,也就是说resume像函数调用一样使用,yield像return语句一样使用。coroutine的灵活性也体现在这种通过resume-yield的值传递上。


本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Lua中的协同程序 coroutine 的相关文章

  • 如何在 Lua 中下载文件,但在运行时写入本地文件

    我正在尝试制作一个更新程序 以便当我的 Lua 应用程序过时时它将使用LuaSocket下载较新的 exe 文件 可以运行我的 Lua 代码 在这个更新程序中 我希望它显示到目前为止已下载的数量 但是 通过以下 HTTP 请求 它会阻止应用
  • 代码说“尝试比较数字<=实例”

    It says Players ninjafox56 PlayerGui Shop ShopGui LightSide ChooseSideL 5 尝试比较数字 Rank game Players LocalPlayer leadersta
  • Lua中运算符~=是什么意思?

    什么是 Lua中的运算符是什么意思 例如 在以下代码中 if x params then the is not equals 这在其他语言中是等价的
  • Lua:“拖动”数组中的元素序列

    我正在尝试创建一个函数 将连续数量的元素 拖动 到数组中的新位置 并限制为数组的当前大小 其他项目应该围绕 拖动 的项目晃动 例如 如果我的数组有 7 个元素 并且我想拖动中间的三个 1 2 3 4 5 6 7 lt keys a b C
  • 使用 OOP 的闭包方法时如何实现受保护的成员?

    现在我正在使用实施 OOP 的闭包 http lua users org wiki ObjectOrientationClosureApproach在卢阿 下面是一个简短的示例 我的问题发生在尝试实施时stronger heal insid
  • Lua 和序列化闭包

    我正在尝试序列化和反序列化 Lua 闭包 我的基本理解是下面的工厂应该生成闭包 并且Lua在函数和闭包之间没有太多区别 即没有类型 闭包 gt function ffactory x return function return x end
  • Corona/Box2D 检测与非移动静态物体的碰撞

    出于发帖原因 这是我正在尝试做的事情的简单版本 在屏幕上我有一个简单的圆形对象 它是静态的并且不会移动 然后用户可以拖放一条直线 如果该线穿过该圆圈 我希望触发碰撞事件 看来除非其中一个物体正在移动 否则永远不会检测到碰撞 绘制线条时能否检
  • Lua - 尝试调用全局(零值)

    执行此代码时 出现错误 尝试调用全局 forId 零值 function execute args local itemid 526 local bone forId itemid this is where the error occur
  • Lua 如何创建可用于变量的自定义函数?

    对于像 io close 这样的方法 你可以像这样使用它 file close 有没有办法创建一个像这样工作的自定义函数 您可以在变量上调用它 对我来说 我尝试使用它通过使用 string find 查找空格来将参数与文本文件分开 所以在文
  • Lua:冒号符号、“自我”和函数定义与调用

    我对定义 调用 Lua 函数时使用的冒号表示法感到非常困惑 我以为我已经明白了 直到我看到这段代码 function string PatternSafe str return str gsub pattern escape replace
  • Lua中如何获取目录列表

    我需要 LUA 中的目录列表 假设我的目录路径为 C Program Files 我需要该特定路径中所有文件夹的列表以及如何搜索该列表中的任何特定文件夹 Example 需要路径 C Program Files 中所有文件夹的列表 以下是上
  • Lua :: 如何编写加载多个CPU的简单程序?

    我还无法用 Lua 编写一个可以加载多个 CPU 的程序 自从Lua通过协程支持这个概念 http www lua org pil 9 4 html 我相信这是可以实现的 我失败的原因可能是以下之一 这在Lua中是不可能的 我写不出来 an
  • VB6 - Lua 集成

    我想知道是否有人有任何集成 Lua 和 VB6 的技巧 我正在运行一个小型在线角色扮演游戏 添加一些脚本会很棒 嗯 这是可行的 我曾经为 Lua 5 0 2 做过 但找不到文件 在您拥有的选项中 您可以 将 Lua 封装在公开 Lua AP
  • 去掉尾随零和小数点

    使用 Lua 我将数字格式化为可变位数并去掉尾随零 小数点 例如 string format precision f value gsub 0 1 gsub 值的类型为数字 正数 负数 整数 小数 所以任务已经解决了 但出于美学 教育和性能
  • 安装Lua套接字库

    要么我太累了 要么我瞎了 我想学习 Lua 网络 因此我必须安装socketlib 所以我可以轻松地要求它 但我不知道我应该 要求 哪些文件 例子说 local socket require socket 但正如我所说 如果我使用 我不知道
  • Lua中按字符分割字符串

    我有像这样的字符串 ABC DEF 我需要将它们分开 字符并将两个部分分别分配给一个变量 在 Ruby 中 我会这样做 a b ABC DEF split 显然Lua没有这么简单的方法 经过一番挖掘后 我找不到一种简短的方法来实现我所追求的
  • 如何在 emacs lua-mode 中配置缩进?

    完整的 emacs 新手在这里 我在 Ubuntu 上使用 emacs 23 1 1emacs 入门套件 https github com technomancy emacs starter kit 我主要在 lua 模式下工作 安装了pa
  • 如何通过 C API 在自己的环境中执行不受信任的 Lua 文件

    我想通过调用在其自己的环境中执行不受信任的 lua 文件lua setfenv http pgl yoyo org luai i lua setfenv这样它就不会影响我的任何代码 该函数的文档仅解释了如何调用函数 而不解释如何执行文件 目
  • 如何让我的 add 命令找到第一个变量和第二个变量的值,然后将它们加在一起?

    vars values function open file lex file end function lex file local data io open file r for char in data lines do Print
  • gsub 的转义字符串

    我读了一个文件 local logfile io open log txt r data logfile read a print data output n w r 1 2 n t x re S 是的 日志文件看起来很糟糕 因为它充满了各

随机推荐

  • 〖Web全栈开发①〗—网络编程基础(上)

    网络编程基础 网络编程 网络编程概述 TCP IP协议 IP地址 什么是IP IP组成 IP 地址使用过程 查看IP Ip地址分类 子网掩码 端口 socket Socket原理 什么是Socket 2 创建一个tcp socket tcp
  • Redis基础语法

    noSQL 主要解决高并发数据 可以提高访问性能 将低服务器负担 Redis 底层结构 采用键值对存储 工作机制 采用单线程 Redis的数据结构 实用度左至右 string hash list set zset key value key
  • 新博客地址

    现在新的博客地址 https rpz105 com https rpz105 com
  • 【 unity3d 】天空盒的创建和使用

    天空盒 周围环境 天空 注意不是地形 一 创建天空盒材质 1 先创建材质 材质里的Shader里找Skybox 有3个制作方式 但是他们的渲染效果一样 只是制作方式不一样
  • LaTeX基本命令使用教程(清晰实例)(Overleaf平台)(论文排版)

    前言 本文是笔者在学习LaTeX的记录文档 主要是一些常用命令 发至博客分享给大家 笔者的感受是熟悉这些常用命令后即可上手编辑简单的论文 效率很高 体验比word好很多 希望本文能够对LaTeX的初学者有所帮助 有任何问题可以在评论区留言
  • 存储过程进行数据合并导入

    CREATE PROCEDURE sp mytest1 mytype int AS declare pro varchar 50 declare pro1 varchar 50 select pro typename from table1
  • web浏览器访问后端提示‘没有javascript支持,将不能正常工作’

    如图提示 网上找了一下解决办法 说是可能浏览器js支持没有开启 但我的浏览器js支持是开启的 后面清理了下浏览器的缓存 问题解决
  • 如何使用 Kubernetes 监测定位慢调用

    监控作者 李煌东 大家好 我是阿里云的李煌东 今天我为大家分享 Kubernetes 监测公开课第四节 如何使用 Kubernetes 监测定位慢调用 今天的课程主要分为三大部分 首先我会介绍一下慢调用的危害以及常见的原因 其次我会介绍慢调
  • Java&JS时间格式转化

    时间格式转化 一 Java格式转化 1 1 接收前端传值转化 1 2 String转化LocalDate 1 3 LocalDate与Date相互转换 二 Javascript格式转化 2 1 JS时间格式转化 一 Java格式转化 1 1
  • openswan中ISAKMP交互过程关键函数接口

    1 ISAKMP交互过程中关键函数接口 下面分别说明不同的阶段和模式下的函数接口以及对应的报文 2 第一阶段 Phase I 主模式函数接口 发送端 响应端 main outI1 主模式第一包
  • MySQL中的索引事务(1)索引----》数据库运行的原理知识+面试题~

    本篇文章主要讲述MySQL索引事务 所谓的索引index就是指 目录 索引存在的意义 加快查找的速度 省略了遍历的过程 但付出了一定的代价 付出的代价如下 1 需要付出额外的空间代价来保存索引数据 2 索引可能会拖慢新增 删除 修改数据的速
  • 华为OD机试真题-最差产品奖【2023.Q1】

    题目内容 题目描述 A公司准备对他下面的N个产品评选最差奖 评选的方式是首先对每个产品进行评分 然后根据评分区间计算相邻几个产品中最差的产品 评选的标准是依次找到从当前产品开始前M个产品中最差的产品 请给出最差产品的评分序列 输入描述 第一
  • Windows terminal + WSL 美化教程的笔记——解决遇到的问题

    文章目录 前言 问题1 如何打开Windows Terminal 的设置 修改配置文件 问题2 打开windows terminal有更新提示怎么办 问题3 打开windows terminal报错怎么办 参考文献 前言 学习过程中突感字体
  • vaultwarden密码库 搭建流程

    系统工程 建设篇 第二章 vaultwarden密码库 搭建流程 系统工程 建设篇 系列文章回顾 前言 前置条件 实施步骤 注意事项 浏览器插件下载链接 部署 vaultwarden密码库 宝塔面板配置docker 开启docker服务 从
  • python连接clickhouse使用方法

    前沿 clickhouse现在作为分布式存储成熟的解决方案 在python开发中经常会用到clickhouse的连接方案 下面所列一个简单的连接clickhouse的写法 正文 from clickhouse driver import C
  • 焉建伟:3.31黄金走势看涨看跌?黄金原油今日如何操作? 实时策略

    消息面 美东时间周二 美国媒体援引两名知情人士的话报道 拜登周三预计将在匹兹堡宣布2 25万亿美元的一揽子基础设施和就业支持计划 具体而言 大约6500亿美元会被用于重建美国基础设施 如道路 桥梁 高速公路和港口 4000亿美元用于老年人和
  • 蓝桥杯单片机前言(经验分享)

    本人在今年省赛的获得了省一等奖 这是战利品hhh 国赛由于没有好好准备 所以没有取得好名次 已经后悔了555 个人经历 当时是寒假开始学习蓝桥杯单片机开发板的 本人情况是有模电 电路理论基础 c语言基础 当时差不多忘记完了 没有51和模电基
  • 六轴融合算法

    先说什么叫六轴融合 在3Dof姿态追踪功能中 最主要的传感器就是陀螺仪 Gyroscope 它可以提供3个轴的角加速度 对时间进行积分 就可以得出物体旋转的方向角度 但是因为硬件精度等各方面原因 会产生误差 随着时间的累积 计算得到的角度误
  • 活动回顾|解锁 AIGC 密码,探寻企业发展新商机

    5月24日 Google Cloud 与 Cloud Ace 联合主办的线下活动顺利落下帷幕 本次活动 有近 40 位企业精英到场支持 三位 Google Cloud 演讲嘉宾就本次活动主题 为大家带来了比较深度的演讲内容 干货满满 以下的
  • Lua中的协同程序 coroutine

    int running 1 int lua finish lua State L running 0 printf lua finish called n return 0 int lua sleep lua State L printf