Lua中的协程Coroutine

2023-11-16

一、协程是什么?

  (1)线程

  首先复习一下多线程。我们都知道线程——Thread。每一个线程都代表一个执行序列。

  当我们在程序中创建多线程的时候,看起来,同一时刻多个线程是同时执行的,不过实质上多个线程是并发的,因为只有一个CPU,所以实质上同一个时刻只有一个线程在执行。

  在一个时间片内执行哪个线程是不确定的,我们可以控制线程的优先级,不过真正的线程调度由CPU的调度决定。

  (2)协程

  那什么是协程呢?协程跟线程都代表一个执行序列。不同的是,协程把线程中不确定的地方尽可能的去掉,执行序列间的切换不再由CPU隐藏的进行,而是由程序显式的进行。

  所以,使用协程实现并发,需要多个协程彼此协作。

 

二、resume和yeild的协作。

  resume和yeild的协作是Lua协程的核心。这边用一幅图描述一下,有一个大体的印象。对照下面的coroutine库的详细解释和最后的代码,应该可以搞清楚协程的概念了。

  注:这是在非首次resume协程的情况下,resume和yield的互相调用的情况。如果是首次resume协程,那么resume的参数会直接传递给协程函数。

 

 

三、coroutine库详解

(1)coroutine.create (f)

  传一个函数参数,用来创建协程。返回一个“thread”对象。

 

(2)coroutine.isyieldable ()

  如果正在运行的协程可以让出,则返回真。值得注意的是,只有主协程(线程)和C函数中是无法让出的。

 

(3)coroutine.resume (co [, val1, ···])

  这是一个非常重要的函数。用来启动或再次启动一个协程,使其由挂起状态变成运行状态。

  可以这么说,resume函数相当于在执行协程中的方法。参数Val1...是执行协程co时传递给协程的方法。

  首次执行协程co时,参数Val1...会传递给协程co的函数;

  再次执行协程co时,参数Val1...会作为给协程co中上一次yeild的返回值。

  不知道这句话大家理解了没,这是协程的核心。如果没理解也不用急,继续往下看,稍后我会详细解释。

  resume函数返回什么呢?有3种情况:

  1)、如果协程co的函数执行完毕,协程正常终止,resume 返回 true和函数的返回值。

  2)、如果协程co的函数执行过程中,协程让出了(调用了yeild()方法),那么resume返回true和协程中调用yeild传入的参数。

  3)、如果协程co的函数执行过程中发生错误,resume返回false与错误消息。

  可以看到resume无论如何都不会导致程序崩溃。它是在保护模式下执行的。

 

(4)coroutine.running ()

  用来判断当前执行的协程是不是主线程,如果是,就返回true。

 

(5)coroutine.status (co)

  返回一个字符串,表示协程的状态。有4种状态:

  1)、running。如果在协程的函数中调用status,传入协程自身的句柄,那么执行到这里的时候才会返回running状态。

  2)、suspended。如果协程还未结束,即自身调用了yeild或还没开始运行,那么就是suspended状态。

  3)、normal。如果协程Aresume协程B时,协程A处于的状态为normal。在协程B的执行过程中,协程A就一直处于normal状态。因为它这时候既不是挂起状态、也不是运行状态。

  4)、dead。如果一个协程发生错误结束,或正常终止。那么就处于dead状态。如果这时候对它调用resume,将返回false和错误消息。

 

(6)coroutine.wrap (f)

  wrap()也是用来创建协程的。只不过这个协程的句柄是隐藏的。跟create()的区别在于:

  1)、wrap()返回的是一个函数,每次调用这个函数相当于调用coroutine.resume()。

  2)、调用这个函数相当于在执行resume()函数。

  3)、调用这个函数时传入的参数,就相当于在调用resume时传入的除协程的句柄外的其他参数。

  4)、调用这个函数时,跟resume不同的是,它并不是在保护模式下执行的,若执行崩溃会直接向外抛出。

 

(7)coroutine.yield (···)

  使正在执行的函数挂起。

  传递给yeild的参数会作为resume的额外返回值。

   同时,如果对该协程不是第一次执行resume,resume函数传入的参数将会作为yield的返回值。

 

四、例子进阶。

 (1)、例子1:简单实用resume、yield,如下:

coco = coroutine.create(function (a,b)
    print("resume args:"..a..","..b)
    yreturn = coroutine.yield()
    print ("yreturn :"..yreturn)
end)
coroutine.resume(coco,0,1)
coroutine.resume(coco,21)

输出:

resume args:0,1
yreturn :21

 

 

(2)、例子2:简单使用wrap,如下:

coco2 = coroutine.wrap(function (a,b)
    print("resume args:"..a..","..b)
    yreturn = coroutine.yield()
    print ("yreturn :"..yreturn)
end)
print(type(coco2))
coco2(0,1)
coco2(21)

输出:

function
resume args:0,1
yreturn :21

很明显,wrap的使用更方便。

 

(3)、如果还没有足够的理解,且看我放大招,看这个例子:

function status()
    print("co1's status :"..coroutine.status(co1).." ,co2's status: "..coroutine.status(co2))
end

co1 = coroutine.create(function ( a )
    print("arg is :"..a)
    status()
    local stat,rere = coroutine.resume(co2,"2")
    print("resume's return is "..rere)
    status()
    local stat2,rere2 = coroutine.resume(co2,"4")
    print("resume's return is "..rere2)
    local arg = coroutine.yield("6")
end)
co2 = coroutine.create(function ( a )
    print("arg is :"..a)
    status()
    local rey = coroutine.yield("3")
    print("yeild's return is " .. rey)
    status()
    coroutine.yield("5")
end)
--主线程执行co1,传入字符串“main thread arg”
stat,mainre = coroutine.resume(co1,"1")
status()
print("last return is "..mainre)

用一个函数status()输出2个协程的状态,最后输出如下:

arg is :1
co1's status :running ,co2's status: suspended
arg is :2
co1's status :normal ,co2's status: running
resume's return is 3
co1's status :running ,co2's status: suspended
yeild's return is 4
co1's status :normal ,co2's status: running
resume's return is 5
co1's status :suspended ,co2's status: suspended
last return is 6

 

(4)、最后附一个云风在Lua5.3参考手册中给出的例子:

function foo(a)
    print("foo", a)
    return coroutine.yield(2 * a)
end

co = coroutine.create(function ( a, b )
    print("co-body", a, b)
    local r = foo(a + 1)
    print("co-body", r)
    local r, s = coroutine.yield(a + b, a - b)
    print("co-body", r, s)
    return b, "end"
end)

print("main", coroutine.resume(co, 1, 10))
print("main", coroutine.resume(co, "r"))
print("main", coroutine.resume(co, "x", "y"))
print("main", coroutine.resume(co, "x", "y"))

输出如下:

co-body    1    10
foo    2
main    true    4
co-body    r
main    true    11    -9
co-body    x    y
main    true    10    end
main    false    cannot resume dead coroutine
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Lua中的协程Coroutine 的相关文章

  • Lua中如何获取目录列表

    我需要 LUA 中的目录列表 假设我的目录路径为 C Program Files 我需要该特定路径中所有文件夹的列表以及如何搜索该列表中的任何特定文件夹 Example 需要路径 C Program Files 中所有文件夹的列表 以下是上
  • Lua中如何对数字表求和?

    Lua有内置的吗sum 功能 我似乎找不到一个 我几乎翻遍了文档中的所有地方 或许table sum 或类似的东西 以遵循当前的约定 但由于我找不到它 我不得不实现它 function sum t local sum 0 for k v i
  • 在 Corona sdk 上保存高分?

    我想保存游戏中创建的高分 并且当玩家点击高分按钮时可以在主菜单中看到 有人可以帮助我吗 您可以使用SQLITE https docs coronalabs com api library sqlite3 index html将高分保存到数据
  • 如何解密Lua字节码?

    早上好 我正在尝试破译 Moon 字节码 但我无法以任何方式 有人可以帮助我吗 我有这个 例如 code 27 76 117 97 81 0 1 4 4 4 8 0 如何将此字节码解密为文本 我已经在这里搜索 http www asciit
  • 为什么 LuaJIT 和 Lua 中的数字舍入格式不同?

    Using string format 据说遵循 Csprintf 在 LuaJIT 轮次中格式化数字与我尝试过的所有其他 Lua 解释器不同 lua v Lua 5 4 1 Copyright C 1994 2020 Lua org PU
  • Kong - 验证上游 ssl(ssl_proxy 打开)

    我已经成功为 API 安装了 kong 网关 该 API 通过上游负载平衡到多个目标 应用程序服务器 现在 我有一个我的应用程序服务器的自签名证书 kong 和目标之间的 ssl 握手应该失败 我推断 kong 不验证上游证书 经过一些研究
  • 如何在 Lua 中实现 OO?

    Lua 没有内置对 OO 的支持 但它允许您自己构建它 您能否分享一些实现面向对象的方法 请为每个答案写一个例子 如果您有更多示例 请发布另一个答案 我喜欢将 OOP 视为容器 对象 内的数据封装以及可以使用该数据完成的操作子集 还有很多内
  • 使用 FastCGI 运行 Lua 脚本

    我目前正在尝试找出使用 FastCGI 与 lighttpd 或 Nginx 一起运行 Lua 脚本的方法 我唯一能挖到的是WSAPI http keplerproject github com wsapi 开普勒计划的一部分 但我想知道是
  • Lua 从 5.1 更新 - LUA_GLOBALSINDEX 问题

    我最近将旧的 Lua 5 1 项目更新到了该库的最新版本 但遇到了问题LUA GLOBALSINDEX 它变得不确定 我只用过它lua getfield函数 像这样 void luastartgame void if startgamefu
  • 比较 Lua 中的日期

    我有一个带有日期表的变量 如下所示 table day number 15 year number 2015 month number 2 如何获取当前日期与上述日期之间的天数 非常感谢 您可以使用os time 将表转换为秒并获取当前时间
  • 如何在 emacs lua-mode 中配置缩进?

    完整的 emacs 新手在这里 我在 Ubuntu 上使用 emacs 23 1 1emacs 入门套件 https github com technomancy emacs starter kit 我主要在 lua 模式下工作 安装了pa
  • 如何在lua中获取shell脚本的返回码?

    我正在lua中执行一个脚本 os execute sh manager scripts update system sh f 我想获得脚本的输出 如果退出状态为 7 则返回 7 I tried local output os execute
  • 如何通过 C API 在自己的环境中执行不受信任的 Lua 文件

    我想通过调用在其自己的环境中执行不受信任的 lua 文件lua setfenv http pgl yoyo org luai i lua setfenv这样它就不会影响我的任何代码 该函数的文档仅解释了如何调用函数 而不解释如何执行文件 目
  • SHA2 512 的改编给出了不正确的结果

    我正在尝试调整 SecureHashAlgorithm 的纯 Lua 实现here http lua users org wiki SecureHashAlgorithm对于 SHA2 512 而不是 SHA2 256 当我尝试使用改编时
  • lua 和 walk_block 中的 pandoc 过滤器

    我正在尝试应用一个 LUA 过滤器 该过滤器只会更改文档的正文 而不影响元数据 而且比我想象的要难 过滤器应将文本添加到内联元素和块元素的前面和后面 如果它适用于内联元素 这里Code 对于块元素失败CodeBlock function P
  • 克隆一个lua状态

    最近 我在使用C 和Lua进行开发时遇到了很多困难 我的情况是 由于某种原因 我的 C 程序中可能有数千个 Lua 状态 但这些状态在初始化后应该是相同的 当然 我可以为每个状态执行 luaL loadlibs 和 lua loadfile
  • 适用于 IEEE 802.15.4 的 Wireshark Lua 解析器 - DissectorTable 名称?

    我正在lua中开发wireshark解析器来解析基于802 15 4的自定义协议 不幸的是我无法找出正确的 DissectorTable 名称 table DissectorTable get wpan wpan does not work
  • 如何从 Lua 字符串中删除所有特殊字符、标点符号和空格?

    在Lua中 我只能找到其他语言的示例 如何从字符串中删除所有标点符号 特殊字符和空格 所以 举例来说 s t r i p p e d会成为stripped In Lua 模式 https www lua org manual 5 3 man
  • 模式 ^u.meta(\.|$) 未按预期工作

    我有这个模式 u meta 预期行为 u meta 将匹配所有角色 例如 u meta u meta admin u meta admin system u meta 它不应该匹配如下所示的内容 u meta admin u meta ad
  • 在 Lua 中更改元表会破坏冒号运算符

    在学习Lua的过程中 我借用了一些代码here http lua users org wiki StringIndexing使用字符串索引 正是这样 getmetatable index function str i return stri

随机推荐

  • yarn创建vue项目报错解决

    1 使用yarn create vue创建项目时报如下错误 2 原因是由于安装包目录和bin目录不在统一磁盘下 查看方法 查看bin目录 yarn global bin 查看安装包目录 yarn global dir 3 解决 1 将yar
  • 代码审计工具之Fortify安装以及初步使用

    目录 1 Fortify Fortify工具介绍 1 Fortify Fortify工具介绍 Fortify SCA 是一个静态的 白盒的软件源代码安全测试工具 它通过内置的五大主要分析引擎 数据流 语义 结构 控制流 配置流等对应用软件的
  • 【Transformer】9、CrossFormer:A versatile vision transformer based on cross-scale attention

    文章目录 一 背景 二 动机 三 方法 3 1 Cross scale Embedding Layer CEL 3 2 Cross former Block 3 2 1 Long Short Distance Attention LSDA
  • 解决RuntimeError: CUDA unknown error - this may be due to an incorrectly set up environment

    RuntimeError CUDA unknown error this may be due to an incorrectly set up environment e g changing env variable CUDA VISI
  • IDEA代码规范插件(CheckStyle插件、alibaba插件)

    IDEA代码规范插件 CheckStyle插件 alibaba插件 代码规范插件 CheckStyle插件 alibaba插件 代码规范插件 CheckStyle插件 1 安装 打开idea的file settings plugins 再搜
  • 关于 微软商店无法加载页面 显示错误代码0x80131500的解决办法

    目录 一 误删系统文件导致Microsoft Store无法打开 1 运行 SFC 和 DISM 2 尝试修复或者重置微软应用商店 3 重新部署 Microsoft Store 4 运行Windows疑难解答 5 对系统镜像进行无损修复 二
  • 渗透测试——提权方式总结

    内容整理自网络 一 什么是提权 提权就是通过各种办法和漏洞 提高自己在服务器中的权限 以便控制全局 Windows User gt gt System Linux User gt gt Root 二 怎样进行提权 提权的方式有哪些 1 系统
  • AI算法工程师面试题基础精选

    AI算法工程师的相关面试题包括机器学习 深度学习以及强化学习等等 在面试时由于涉及范围比较广泛 一般面试官不会问一些比较深比较偏的问题 一般都会结合你经手的项目或者在校期间的项目进行一些算法的基础问题进行提问 在这里我们对在面试中常见中的基
  • 分享CSS3里box-shadow属性的使用方法,包括内阴影box-shadow:inset

    一 box shadow语法 box shadow none inset 可选值 不设置 为外投影 设置 为内投影 x offset 阴影水平偏移量 正方向为right y offset 阴影垂直偏移量 正方向为bottom blur ra
  • 记录好项目D16

    记录好项目 你好呀 这里是我专门记录一下从某些地方收集起来的项目 对项目修改 进行添砖加瓦 变成自己的闪亮项目 修修补补也可以成为毕设哦 本次的项目是个电影购票系统 一 系统介绍 前台 普通用户注册 登录 注销 用户信息修改 邮箱 密码 头
  • Qt编译时,出现 first defined here,原因及解决方法

    场景 今天想着把之前写过的模块 都整合到一起 结果一编译程序就出现这个错误 原因 因为头文件出现重复包含了 后来我想了一下 我每个模块都是独立编写的 怎么会重复呢 然后去了pro文件里看了一下 里面果然有两个一模一样的头文件名 QT诚不欺我
  • Newtonsoft.Json基本使用

    Newtonsoft Json基本使用 使用强类型进行序列化反序列化 准备一个学生类 public class Student public string Name get set public int Age get set public
  • Android系统启动流程

    文章目录 总结 1 rc脚本语法规则 2 init进程启动 init first stage init second stage 3 ServiceManager启动 4 Zygote进程启动 5 Launcher启动 总结 android
  • [sql]使用sql语句增加列,并且设置默认值

    有的时候 我们需要对已存在的表进行插入列的情况 当然 可以使用navicat等工具直接可视化操作 命令行的话 如下 alter table 表名 add column 列名 数据类型 default 默认值 demo alter table
  • flutter开发实战-MethodChannel实现flutter与iOS双向通信

    flutter开发实战 MethodChannel实现flutter与iOS双向通信 最近开发中需要iOS与flutter实现通信 这里使用的MethodChannel 如果需要flutter与Android实现双向通信 请看 https
  • O-RAN专题系列-38:管理面-WG4.MP.V07-规范解读-第5章-软件管理

    作者主页 文火冰糖的硅基工坊 文火冰糖 王文兵 的博客 文火冰糖的硅基工坊 CSDN博客 本文网址 目录 第5章 软件管理 5 1 Software Package 5 2 Software Inventory消息 5 3 Software
  • @Transactional事务注解

    1 实现原理 基于AOP面向切面的 它将具体业务与事务处理部分解耦 代码侵入性很低 2 Transactional注解可以作用于哪些地方 作用于类 当把 Transactional 注解放在类上时 表示所有该类的public方法都配置相同的
  • 使用正则表达式验证邮箱格式?

    需满足的验证逻辑 1 之前必须有内容且只能是字母 大小写 数字 下划线 减号 点 2 和最后一个点 之间必须有内容且只能是字母 大小写 数字 点 减号 且两个点不能挨着 3 最后一个点 之后必须有内容且内容只能是字母 大小写 数字且长度为大
  • python @register_第7.21节 Python抽象类—register注册虚拟子类

    上两节介绍了Python抽象类的真实子类的定义和使用 本节介绍另一种抽象类的实现方法 虚拟子类方法 一 相关概念 虚拟子类是将其他的不是从抽象基类派生的类 注册 到抽象基类 让Python解释器将该类作为抽象基类的子类使用 因此称为虚拟子类
  • Lua中的协程Coroutine

    一 协程是什么 1 线程 首先复习一下多线程 我们都知道线程 Thread 每一个线程都代表一个执行序列 当我们在程序中创建多线程的时候 看起来 同一时刻多个线程是同时执行的 不过实质上多个线程是并发的 因为只有一个CPU 所以实质上同一个