lua 延时和定时器

作者:王海洋
更新时间:2021年4月2日
关键词:延时,定时器,timer

目录

  • 延时和定时器
    • 简介
    • API说明
    • 实现流程
      • 创建
      • 消亡
        • 自动消亡
        • 手动消亡
      • 判断定时器状态
    • 知识拓展
    • 示例
    • 常见问题
    • 相关资料以及购买链接

延时和定时器

简介

在luat脚本程序中,往往需要用到延时和等待等逻辑功能。例如,你想得到每隔30秒查询当前内存,这里就需要用到延时和定时器。在每次打印后加上一个30秒的定时器或者30秒的延迟,既可以实现这个功能。本篇文章将介绍2个延时函数和4个定时器函数以及一个判定定时器激活状态的函数,讲解这些函数如何使用以及在什么环境下使用。

API说明

详细的API介绍见sys API章节和rtos API章节

实现流程

创建

sys.wait():

  • sys.wait(ms):既属于延时也属于定时器,但只能适用于任务函数中(task)。它功能就是被调用时挂起当前协程,等延时时间结束结束后再继续执行剩下的协程功能。原理是先去启动一个定时器,将当前的协程挂起。如需在定时器计时结束前退出,可使用coroutine.resume接口重新激活协程。
    创建也很简单,例子:sys.wait(1000) 会停止当前的协程任务,等1000ms后延时函数正常消亡,继续回来执行剩下脚本。

rtos.sleep():

  • rtos.sleep(ms):属于底层延时函数,可用于任何环境。函数执行原理:执行该函数会将操作系统中的Lua虚拟机任务挂起,在计时结束前无 法退出。
    创建示例:rtos.sleep(1000) 执行后,Lua虚拟机任务就会被挂起,1000ms后函数正常消亡,继续执行Lua虚拟机任务。

接下来是介绍定时器,共有四种定时器,他们各有各的特点。所以我们在使用时一定要记清楚这些定时器的特点,挑选适合当前程序需求的定时器使用。在luat脚本程序中,同时运行的定时器是有数量限制的。8910平台的Luat最多支持50个定时器,如何理解50个定时器?在下面的知识扩展里详细讲解了。sys.timerStart()和function sys.timerLoopStart()的返回值是定时器ID,这个可以用来判断是否为同一个
定时器。或者也可以通过定时器的回调函数和回调参数是否相同来判断。
sys.timerStart():

  • sys.timerStart(fnc,ms,…):属于定时器,单词定时器,适用场景不限定。第一个参数是回调函数,第二个是超时时间(ms),第三个是回调函数的参数,返回值是定时器ID。在创建前会查找当前开启的定时器,有相同定时器ID或者回调函数和回调参数相同时,就会关闭签一个定时器,再创建新的定时器,重新计时。

function sys.timerLoopStart():

  • function sys.timerLoopStart(fnc,ms, …):属定时器,循环定时器,适用场景不限定。用法特点同单此定时器几乎相同。唯一区别就是单此和多次循环。

sys.wait()(仅适用于task):

  • function sys.wait(ms):延时介绍过,属于延时也属于定时器。单次定时器,适用场景仅限定task内。

sys.waitUntil()(仅适用于task):

  • sys.waitUntil(id,ms):属于定时器,单次定时器,适用场景不限定。第一个参数是消息ID,第二个是超时间。sys.waitUntil()的特性与sys.timerStart()的完全一样,区别是sys.waitUntil()仅限于task内部使用。特性与详细介绍看下图。

lua 延时和定时器_第1张图片

消亡

自动消亡
  1. sys.timerStart:收到定时器事件,执行回调函数后,lib中自动消亡
  2. sys.timerLoopStart:收到定时器事件,每次执行回调函数后,lib中重新创建
  3. sys.wait:挂起的task收到定时器事件后,lib中自动消亡
  4. sys.waitUntil:挂起的task收到消息事件或者定时器事件后,lib中自动消亡
手动消亡
手动消亡有两种方式:sys.timerstop()和sys.timerstopAll()

1.sys.timerstop(val,…)
参数是定时器ID或者定时器的回调函数和回调参数。使用这个函数可以关闭指定的一个定时器。
返回值为nil
lua 延时和定时器_第2张图片

2.sys.timerstopAll(fnc)
功能:关闭sys.timerStart和sys.timerLoopStart创建的某一个回调函数的所有定时器
参数:需要关闭的定时器回调函数。
返回值:nil

lua 延时和定时器_第3张图片

已经消亡的定时器,再去执行stop不会产生异常

判断定时器状态

sys.timerlsActive()
功能:判断“通过timerStart或者timerStart创建的定时器”是否处于激活状态
参数:通过timerStart或者timerStart创建的定时器返回的定时器id或者回调函数与回调参数。

参数:
参数为回调函数与回调参数时,如果处于激活状态,则返回bool类型的true,否则返回nil。

返回值:
参数为定时器ID时,如果处于激活状态,则返回function类型的定时器回调函数,否则返回nil
例子:

local function timerCbFnc2(tag)
    log.info("timerCbFnc2",tag)
end

sys.timerStart(timerCbFnc2,5000,"test")

sys.taskInit(function()
    sys.wait(3000)
    log.info("after 3 senonds, timerCbFnc2 test isActive?",sys.timerIsActive(timerCbFnc2,"test"))
    
    sys.wait(3000)
    log.info("after 6 senonds, timerCbFnc2 test isActive?",sys.timerIsActive(timerCbFnc2,"test"))
end)

结果:
image.png


知识拓展

1.8910平台的Luat最多支持50个定时器,如何理解50个定时器?
看下列两端代码,猜测,最后分别还有几个定时器在运行。

sys.taskInit(function()
    for i=1,50 do
        sys.timerStart(function() end,1000)
    end
    log.info("不考虑其它代码中定时器的使用")
    log.info("运行到这里,同时存在多少个定时器?")
end)
sys.taskInit(function()
    for i=1,50 do
        sys.wait(1000)
    end
    log.info("不考虑其它代码中定时器的使用")
    log.info("运行到这里,同时存在多少个定时器?")
end)

第一段代码是创建50个回调函数相同,延时时间相同的单此定时器。通过前面的介绍可知, 如果回调函数和回调参数都相同的两个sys.timerStart()定时器,可视为同一定时器。当第一个sys.timerStart(function() end,1000)创建好后,再创建第二个sys.timerStart(function() end,1000)时,就会查找当前存在的定时器里,是否有相同的定时器,如果就就会将第一个关闭,创建第二个相同的定时器,并重新开始计时。所以第一个代码段最后吃剩一个定时器在运行。
第二段代码是创建50个sys.wait(1000)。当创建第一个sys.wait(1000)后,这个协程就会被挂起。1000ms后,继续执行剩下的程序,创建下一个sys.wait(1000)。所以,最后也只剩一个定时器。

下面这段代码,通过改变回调参数来同时创建50个sys.timerLoopStart(log.info,1000,“nCounter1”,i)。但看打印结果会发现,没到50个。因为打印出来的数量只是sys.timerLoopStart(log.info,1000,“nCounter1”,i)的数量,还有sys.wait(5000)等一些定时器没算在内。

    local function wait1()
    sys.wait(5000)
    for i=1,50 do
        sys.timerLoopStart(log.info,1000,"nCounter1",i)
    end
end

sys.taskInit(wait1)

示例

详细的API demo见The Timer demo章节

1.waitUntil()、wait()

  • waitUntil()和wait()sys.wait和sys.waitUntil只能用在task中,或者被task的主函数直接或者间接调用。
local function IndirectCall()
    sys.waitUntil("MSG_ID",5000)
end

sys.taskInit(function()
    sys.wait(5000)
    IndirectCall()
    log.info("sys.wait和sys.waitUntil只能用在task中")
    log.info("只能被task的主函数直接或者间接调用")
end)

2.timerStart()

  • timerStart()是单此定时器
local function publicTimerCbFnc(tag)
    log.info("publicTimerCbFnc",tag)
end

sys.timerStart(publicTimerCbFnc,8000,"first")
local timerId2 = sys.timerStart(publicTimerCbFnc,8000,"second")
sys.timerStart(publicTimerCbFnc,8000,"third")

3.timerLoopStart()

  • timerLoopStart()是循环定时器
local nCounter = 0

sys.taskInit(function ()
    while true do
        nCounter = nCounter+1
        sys.wait(1000)
    end
end)

sys.timerLoopStart(log.info,1000,"nCounter1",nCounter)
--sys.timerLoopStart(log.info,1000,"nCounter1",0)

sys.timerLoopStart(function() log.info("nCounter2",nCounter) end,1000)0,"first")

常见问题

1,定时器精度问题
Luat开发最小仅支持5毫秒的定时器,超时时间最小1ms(实际支持的最小时间是5ms,小于5ms的时间都被转化为5ms) 超时间最大0x7FFFFFFF(24.85天)。
另外毫秒级的定时器的误差较大,原因可参考Luat应用脚本运行框架

相关资料以及购买链接

延时和定时器 相关资料
sys API章节和rtos API章节
延时和定时器demo说明
相关开发板购买链接
Air724UG开发板
Air724 开发板使用说明

你可能感兴趣的:(lua)