且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

如何在Lua中的特定日期和特定时间执行全局功能?

更新时间:2023-02-16 13:05:05

我注意到您的代码存在一些问题.首先,一半时间,您要与os.time(一个函数)和os.time()(一个数字)进行比较.其次,您将进入until (os.time == target);的无限循环,因为os.time除非更改,否则永远不会改变.

I've noticed a few issues with your code. First of all, half the time, you're comparing to os.time which is a function and os.time() which will be a number. Secondly, you're going into an infinite loop with until (os.time == target);, since os.time will never change unless you change it.

即使这样,如果您正确地与os.time()进行比较,也将进入无限循环以检查Lua VM一直在最大程度地消耗CPU使用率的时间,因为不会进行无限循环.这将可能冻结该过程,这可能就是您所说的崩溃和燃烧".

Even then, if you were correctly comparing with os.time(), going into an infinite loop to check the time all the time is going to max out CPU usage for the Lua VM, as infinite loops are wont to do. This will probably freeze up the process, which might be what you mean by "crash and burn."

最后但并非最不重要的一点是,将当前时间与将来的时间与==进行比较通常是一个坏主意,因为条件恰好在准确的期望时间内执行的可能性很小.

Last but not least, comparing the current time to a time in the future with an == is generally a bad idea, due to the low probability of the condition executing precisely during the exact desired time.

我建议您尽可能睡觉,直到准备好执行最早的任务为止.这样,您可以避免在不断轮询的情况下占用不必要的CPU时间.在Lua中,您可以执行以下操作.

I'd recommend sleeping as long as possible until the earliest task is ready to be carried out. This way, you avoid taking up any unnecessary CPU time with constant polling. From Lua, you could do something like this.

local target = os.time{year = 2013, month = 11, day = 21, hour = 9, min = 30}

local function sleep(s) -- wait for `s` seconds
    if type(s) ~= 'number' then
        error's is not a number'
    elseif s < 1 then
      return
    end
    s = math.floor(s)

    -- Windows (delay range limited to 0-9999)
    --os.execute('choice /n /d:y /t:' .. math.min(s, 9999) .. ' > NUL')

    -- *nix
    os.execute('sleep ' .. s)
end

local d
repeat
    d = target - os.time()
    if d <= 0 then break end
    sleep(d) -- sleep for the difference
until false

print'Target time has arrived.'


理想情况下,您可以通过使用操作系统的调度程序来完成类似的操作,例如 cron (在* nix上)或任务计划程序在Windows上,控制脚本执行的时间.但是,如果您打算通过Lua处理时间安排,请浏览此页面在Lua中编程中.


Ideally, you'd accomplish something like this by having your operating system's scheduler, such as cron on *nix or Task Scheduler on Windows, control the timing of the script's execution. However, if you plan to handle the timing through Lua, have a look through this page in Programming in Lua.

编辑:上次使用我们的sleep函数,我们可以轻松地为Lua中的完整任务计划程序创建基础,该任务计划程序只需几行代码即可处理多个事件.

Making use of our sleep function from last time, we can easily create the foundation for a complete task scheduler in Lua that can handle multiple events with only a few lines of code.

local alarm = {}
local function sort_alarm(a, b) return a.time > b.time end
local function schedule(when, what)
    if os.time() <= when then
        table.insert(alarm, {time = when, event = what})
        table.sort(alarm, sort_alarm)
    else -- What to do when a scheduled event is in the past?
        what()
    end
end
local function run_scheduler()
    local d
    while #alarm > 0 do
        d = alarm[#alarm].time - os.time()
        if d <= 0 then
            -- Pop the latest alarm from the stack and call it.
            table.remove(alarm).event()
        else
            sleep(d)
        end
    end
end

-- Schedule some events.
schedule(os.time{year = 2013, month = 11, day = 22, hour = 9}, function()
    print'This function runs at a specific point in time.'
end)

schedule(os.time() + 30, function()
    print'This function will run 30 seconds from the start of the script.'
end)

schedule(os.time() + 5, function()
    print'This function will run 5 seconds from the start of the script.'
    schedule(os.time() + 10, function()
        print'You can even schedule new functions this way.'
        print'This one will run 15 seconds from the start of the script.'
    end)
end)

local function repeater()
    print'How about a repeating event?'
    print'This function will run every 10 seconds.'
    schedule(os.time() + 10, repeater)
end
schedule(os.time() + 10, repeater)

-- Start the scheduler loop.
run_scheduler()

-- No more events left at this point, thus the script will end.


结束语,我必须注意,如果您打算认真使用此功能,则将来希望将sleep功能替换为更可靠的功能.用户Wiki上有一个页面,其中列出了一些解决方案.如果要碰巧使用LuaJIT,请使用 FFI ,这是从LuaJIT进行的最简单的操作


In closing, I must note that if you plan to use this seriously, you'll want to replace the sleep function with something more robust in the future. There's a page on the users wiki listing some solutions. I'd say it's easiest to do from LuaJIT using the FFI, if you happen to be using it already.