首页 > 其他分享 >lua的协程

lua的协程

时间:2024-04-03 10:12:28浏览次数:13  
标签:协程 coroutine resume yield --- lua co

  lua协程的创建通常是通过coroutine.create(f),其中f就是协程的主体程序,它必须是一个函数。coroutine.create返回一个类型为thread(lua的8种内建类型之一)的变量。

---
--- Creates a new coroutine, with body `f`. `f` must be a Lua function. Returns
--- this new coroutine, an object with type `"thread"`.
---@param f fun():thread
---@return thread
function coroutine.create(f) end

协程的状态和状态切换

  协程有4种状态,分别是:

状态 说明
running 运行状态,协程主体函数正在执行时的状态
suspended 挂起状态,协程调用yeild,或者刚刚创建完成时的状态
normal 正常状态,协程已激活(resume),但是执行序列不在此协程中,通常是协程嵌套时
dead 死亡状态,协程主体函数执行完毕,或者主体函数执行异常,停止后的状态

  下面一个例子展示了协程除normal态的切换例子

#!/usr/bin/lua

local co

function routine()
    print("在协程主体函数执行时,查询到的协程状态:", coroutine.status(co))
    coroutine.yield()
    print("退出协程了")
end

function main()
    co = coroutine.create(routine)
    print("刚创建完协程时的状态:", coroutine.status(co))
    coroutine.resume(co)
    print("调用resume启动协程,yield后的状态:", coroutine.status(co))
    coroutine.resume(co)
    print("刚创建完协程时的状态:", coroutine.status(co))
end

main()

  在理解上面例子前,需要知道yieldresume的作用,类比linux下的调度,协程的resume,就相当于让指定的协程获得执行权,而yield就是协程主动让出执行权。

  上面的例子执行的结果是

刚创建完协程时的状态:	suspended
在协程主体函数执行时,查询到的协程状态:	running
调用resume启动协程,yield后的状态:	suspended
退出协程了
刚创建完协程时的状态:	dead

  这里我特意把控制协程运行相关的代码写在一个单独的main函数里面。为了方便理解,暂且把协程当成线程理解(它俩不是一回事,仅为了好理解),首先main未调用 coroutine.create(routine)时,该进程是单线程的,调用后,此时进程中包含了2个线程,主线程main和子线程routine。当调用coroutine.resume(co)时,主线程让出执行权,子线程开始执行(变成running态),子线程执行到coroutine.yield()后,它又会让出执行权(变成suspended态),回到交给它执行权的主线程中。当子线程的语句执行完毕,它会彻底让出执行权(变成dead态),永远无法再次resume,即使强制调用,也会返回错误`。

还剩余一个normal态未体现出来,下面这个简单的例子可以看到normal

#!/usr/bin/lua

local co1, co2

function routine1()
    print("第一级协程")
    print("在第一级协程查询到的第一级协程状态:", coroutine.status(co1))
    print("在第一级协程查询到的第二级协程状态:", coroutine.status(co2))
    coroutine.resume(co2)
    print("第一级协程退出了")
end

function routine2()
    print("第二级协程")
    print("在第二级协程查询到的第一级协程状态:", coroutine.status(co1))
    print("在第二级协程查询到的第二级协程状态:", coroutine.status(co2))
    print("第二级协程退出了")
end

function main()
    co1 = coroutine.create(routine1)
    co2 = coroutine.create(routine2)
    coroutine.resume(co1)
end

main()

执行结果

第一级协程
在第一级协程查询到的第一级协程状态:	running
在第一级协程查询到的第二级协程状态:	suspended
第二级协程
在第二级协程查询到的第一级协程状态:	normal
在第二级协程查询到的第二级协程状态:	running
第二级协程退出了
第一级协程退出了

resumeyeild传递参数的规则

 &emsp首先看一下这2个函数的介绍

---
--- Starts or continues the execution of coroutine `co`. The first time you
--- resume a coroutine, it starts running its body. The values `val1`, ...
--- are passed as the arguments to the body function. If the coroutine has
--- yielded, `resume` restarts it; the values `val1`, ... are passed as the
--- results from the yield.
---
--- If the coroutine runs without any errors, `resume` returns **true** plus any
--- values passed to `yield` (when the coroutine yields) or any values returned
--- by the body function (when the coroutine terminates). If there is any error,
--- `resume` returns **false** plus the error message.
---@overload fun(co:thread):boolean|any
---@param co thread
---@param val1 string
---@return thread|any
---
---
---启动或者继续执行协程`co`.当第一次对一个协程调用resume时,它开始运行它的函数体.除`co`
---外的参数,`val1`, `...`都会传递给协程的函数体.如果协程已经让出执行权,`resume`
---调用将重新恢复协程的执行;此时传递进去的参数`val1`, `...`将作为yield的返回值。
---
---如果协程运行正常,`resume`返回**true**外加传递给`yield`的任何值(当协程让出执行权时).
---当出错时,`resume`返回**false**外加错误消息.
function coroutine.resume(co, val1, ...) end

---
--- Suspends the execution of the calling coroutine. Any arguments to `yield`
--- are passed as extra results to `resume`.
---
---挂起调用协程的执行.传递给`yield`的所有参数都将作为`resume`的返回值
---@return any
function coroutine.yield(...) end

结合下面这个例子

#!/usr/bin/lua

local co = coroutine.create(function(p1, p2)
    print("传递给协程主函数体的参数:", p1, p2)
    while true do
        local yieldRet;
        yieldRet = coroutine.yield("c", "d")
        print("协程第一次调用yield的返回值列表:", yieldRet)
        local coRet = "f"
        return coRet
    end
end)

local resRet, value1, value2 = coroutine.resume(co, "a", "b")
print("第一次调用resume的返回值列表:", resRet, value1, value2)

resRet, value1 = coroutine.resume(co, "e")
print("第二次调用resume的返回值列表:", resRet, value1)

resRet, value1 = coroutine.resume(co, "g")
print("第三次调用resume的返回值列表:", resRet, value1)

执行结果

传递给协程主函数体的参数:	a	b
第一次调用resume的返回值列表:	true	c	d
协程第一次调用yield的返回值列表:	e
第二次调用resume的返回值列表:	true	f
第三次调用resume的返回值列表:	false	cannot resume dead coroutine

  结合例子,分析过程:

  • 入口程序第一次调用resume,激活协程,进入协程函数体时:这时进行了一次执行权的切换,resume的所有参数"a", "b"(除了第一个thread类型参数),都传递给了协程函数体的参数p1, p2
  • 协程执行序列调用yield让出执行权,执行序列回到入口函数体resume调用的返回前夕, yield的参数"c", "d"将作为resume的从第二开始的返回值列表,执行权回到入口函数体。
  • 入口函数体继续执行序列,第二次调用resume,执行权再次回协程执行序列,此时协程执行序列位于上一步yield调用的返回前夕,resume传递的参数e就作为了yield的返回值,协程执行序列继续执行。
  • 协程函数体执行到返回,让出执行权,返回值作为上一步入口函数体执行序列的第二次resume调用的返回值,执行序列再次回到入口函数体,此时协程死亡,状态变成dead
  • 入口函数体再次执行resume,由于此时协程已经死了,所以resume执行结果是失败的,返回执行结果false和错误信息

标签:协程,coroutine,resume,yield,---,lua,co
From: https://www.cnblogs.com/thammer/p/18112064

相关文章

  • Redis+lua脚本配合AOP限流
    限流Redis脚本限流脚本配合切面注解定义注解:@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)@Documentedpublic@interfaceRateLimiter{/***限流key*/publicStringkey()defaultCacheConstants.RATE_LIMIT_KEY;/**......
  • clion + EmmyLua插件实现Lua的本地调试
    安装好EmmyLua插件后,它会提供两种调试方式:1.使用mobdebug调试2.使用EmmyDebugger调试。mobdebug是用lua写的一个调试模块,基于网络通信(所以依赖luasocket),以字符形式传递调试命令和返回结果。所以使用mobdebug前先需要安装luasocket模块。由于基于网络,所以支持跨机器调试,本机调试......
  • love 2d Lua 俄罗斯方块超详细教程
    源码已经更新在CSDN的码库里:gitclonehttps://gitcode.com/funsion/love2d-game.git一直在找Lua能快速便捷实现图形界面的软件,找了一堆,终于发现love2d是小而美的原生lua图形界面实现的方式。并参考相关教程做了一个更详细的,以便入门。功能如上图,开发过程用了love2d,......
  • 【Lua硬件编程之】电机温度和振动4G远程监测
    【Lua硬件编程之】电机温度和振动4G远程监测1电机温度和振动监测介绍2温振传感器4G上云图示3代码实现讲解(基于FlexLuaDTU01采集器)4参考资料1电机温度和振动监测介绍可通过温振传感器测量电机表面的温度,电机三轴振动速度,电机的振动位移,通过这些物理量来感知电......
  • 基于 FlexLua 开源代码4G远程上报水表电表数值
    基于FlexLua开源代码4G远程上报水表电表数值1采集器和电表、水表连接方式采集器通过485总线可连接不同的水表和电表,每个表的RS485Modbus地址设置为不同即可。采集器通过4G无线传输方式,将采集到的电表数据(比如:三相电压,三相电流,功率因素,有功功率,频率)、水表(用水量)这些数......
  • 协程中Flow的一些特性(冷流,流的连续型、构建器、上下文、指定协程中收集流、流的取消)
    一、冷流Flow是一种类似序列的冷流,flow构建器中的代码知道流被收集的时候才运行。惰性生成:冷流只有在被订阅时才会开始生成数据。在订阅之前,它不会执行任何操作,也不会产生任何数据项。简单来讲就是现学现用,什么时候使用什么时候才调用。比如使用collect就是启动的标志。......
  • 协程&异步编程
    协程,也可以被称为微线程,是一种用户态内的上下文切换技术。简而言之,其实就是通过一个线程实现代码块相互切换执行协程一般应用在有IO操作的程序中,因为协程可以利用IO等待的时间去执行一些其他的代码,从而提升代码执行效率。async事件循环事件循环,可以理解为while循环,在周期性......
  • 在Python中如何使用协程进行并发操作
    在Python中使用协程进行并发操作是一种高效的方式来处理I/O密集型任务或者在单个Python程序内部执行多个操作。本文将详细介绍如何在Python中使用协程进行并发操作,包括协程的基本概念、如何创建和运行协程、如何使用任务来管理多个协程,以及如何利用协程进行并发网络请求等。最......
  • 魔兽世界LUA插件开发
    魔兽世界LUA插件开发1.创建插件1.1创建插件文件夹打开WorldofWarcraft\Interface\AddOns文件下,在该文件夹下创建一个插件名文件夹用来存放插件,如Makubex1.2创建插件文件在该文件夹下创建俩个文件,一个是用来给魔兽世界引入的toc头文件,一个是你自己的lua脚本文件......
  • cron 中开启协程执行任务
    cron中开启协程执行任务‍packagecronimport( "project/internal/jobs" "github.com/robfig/cron/v3")funcRun(){ c:=cron.New(cron.WithSeconds())//每分钟的第40秒执行 c.AddJob("40,*****",jobs.OneMinuteJob{}) //启动一个......