zoukankan      html  css  js  c++  java
  • skynet框架之日程表设计

    参考云风大神的例子,对其进行了改进,支持多次提交单个日程,改变时间后,提前日程触发时间。

    --[[
        t提供了两种方案
        方案1和2
    ]]
    
    local skynet = require "skynet"
    local service  = require "skynet.service"
    
    local schedule = {}
    local service_addr
    
    -- ttime = { month=, day=, wday=, hour= , min= }
    function schedule.submit(ttime)
        
        return skynet.call(service_addr, "lua", ttime)
        -- TOO(do somthing)
        -- skynet.error(" schedule.submit")
    end
    
    function schedule.changetime(ttime)
        local tmp = {}
        for k, v in pairs(ttime) do
            tmp[k] = v
        end
        tmp.changetime = true
        return skynet.call(service_addr, "lua", tmp)
    
    end
    
    skynet.init(function()
        local schedule_service = function()
            local skynet = require "skynet"
            local task  = {session = 0,difftime = 0}
            local tasksession = {}
    
            local function next_time(now, ttime) -- 参数现在的时间,日程时间
                local ntime = {
                    year = now.year,
                    month = now.month,
                    day = now.day,
                    hour = ttime.hour or 0,
                    min = ttime.min or 0,
                    sec = ttime.sec,
                }
                -- skynet.error(now.year,now.month,now.day,now.hour,now.min,now.sec,now.wday)
                -- skynet.error(ttime.year,ttime.month,ttime.day,ttime.hour,ttime.min,ttime.sec,ttime.wday)
                -- skynet.error(ntime.year,ntime.month,ntime.day,ntime.hour,ntime.min,ntime.sec,ntime.wday)
                
                if ttime.wday then -- 每周的活动
                    -- set week
                    assert(ttime.day == nil and ttime.month == nil)
                    ntime.day = ntime.day + ttime.wday - now.wday
                    local t = os.time(ntime)
                    if t < now.time then
                        ntime.day = ntime.day + 7
                    end
                else -- 如果日程时间使日期的话
                    -- set day,no week day
                    if ttime.day then
                        ntime.day = ttime.day
                    end
                    if ttime.month then
                        ntime.month = ttime.month
                    end
                    local t = os.time(ntime) -- 换成秒
                    if t < now.time then --时间和现在比是过去的时间变成下个月或者下一年
                        if ttime.month then
                            ntime.year = ntime.year + 1
                        else
                            ntime.month = ntime.month + 1
                        end
                    end
                end
                skynet.error("next_time ",ntime.year,ntime.month,ntime.day,ntime.hour,ntime.min,ntime.sec,ntime.wday)
                return os.time(ntime) -- 将下次日程的时间换成秒返回
            end
    
            local function changetime(ttime)
                local ctime = math.floor(skynet.time()) --向下取整
                --local now = math.floor(skynet.time())
                skynet.error("changetime",ctime)
                local current = os.date("*t",ctime) --将ctime 转换成*t的表结构
                current.time = ctime -- 保存原来的时间
                if not ttime.hour then -- 如果原来表结构中没有小时,将现在的小时赋值给它
                    ttime.hour = current.hour
                end
                if not ttime.min then -- 如果原来表结构中没有分钟,将现在的分钟赋值给它
                    ttime.min = current.min
                end
                ttime.sec = current.sec -- 现在的秒赋值给它
                local ntime = next_time(current,ttime) -- 计算出下一次日程的时间
    
                skynet.error(string.format("Change time to nex %s",os.date(nil,ntime)))
                skynet.error(string.format("Change time to cur %s",os.date(nil,ctime)))
                local unique_diff = os.difftime(ntime,ctime) -- 方案1计算出下次日程距离现在时间还有多少秒
                --task.difftime = os.difftime(ntime,ctime)
                --skynet.error("changetime task.difftime",task.difftime)
                skynet.error("changetime unique_diff",unique_diff)
                for k, v in pairs(task) do  -- 日期改变了才 遍历日程表,唤醒所有挂起的线程
                    local ttask_diff = 0 --方案1
                    if type(v) == "table" then
                        ttask_diff =  os.difftime(v.time, math.floor(skynet.time())) -- 方案1
                        
                        if unique_diff > ttask_diff then --方案1
                            task[k].difftime = ttask_diff --方案1
                            --task.difftime = ttask_diff 
                        end
                        skynet.error("changetime unique_diff",k,unique_diff)
                        skynet.error("changetime task.difftime",k,task.difftime)
                        skynet.error("changetime ttask_diff",k,ttask_diff)
                        skynet.error("changetime session",k, type(v.co))
                        skynet.wakeup(v.co) -- 唤醒服务
                    end
                end
                skynet.ret()
            end
    
            -- {year = 2020, month=12, day=31, hour=20 , min=30}
            local function submit(_, addr, ttime)
                if ttime.changetime then
                    return changetime(ttime)
                end
                local session = task.session + 1
                task.session = session
                task[session] = {time = 0, address = addr, difftime = 0}-- 方案1
                skynet.error("submit task.session",task.session)
                repeat -- 循环 直到时间到了
                    
                    local now = math.floor(skynet.time()) -- 真的当前时间戳
                    skynet.error(string.format("submit now  %s",os.date(nil,now)))
                    local ctime = now  + task[session].difftime -- 方案1现在的时间+日程距离现在的秒数 = 假的当前的时间戳
                    local ctime = now  + task.difftime -- 方案2
                    skynet.error("submit task[session].difftime",session,task[session].difftime)
                    -- if  ctime > task[session].time then -- 方案2
                    --     break -- 方案2
                    -- end-- 方案2
                    local current = os.date("*t",ctime) -- 变成结构
                    current.time = ctime -- 增加一项time
    
                    local ntime = next_time(current,ttime) -- 计算下次日程时间
                    skynet.error(string.format("submit ntime  %s",os.date(nil,ntime)))
                    skynet.error(string.format("submit ntime  %d",ntime))
                    skynet.error(string.format("submit ctime  %s",os.date(nil,ctime)))
    
                    task[session].time = ntime -- 方案1
                    task[session].co =  coroutine.running()-- 方案1
                    
    
                    local diff =  os.difftime(ntime,ctime)
                    skynet.error("submit sleep",diff,session)
                until skynet.sleep(diff * 100) ~= "BREAK"  -- 休眠diff * 100
    
                task[session] = nil
                skynet.ret() 
            end
    
    
            skynet.start(function()
                skynet.dispatch("lua", submit)
                skynet.info_func(function()
                    local info = {}
                    for k, v in pairs(task) do 
                        if type(v) == "table" then
                            table.insert(info, {
                                time =  os.date(nil, v.time),
                                address =  skynet.address(v.address),
                            })
                        end
                        return  info
                    end
                end)
            end)
        end
        service_addr = service.new("schedule", schedule_service) -- 启动一个服务
    end)
    return  schedule

    方案一主要思路是:在repeat循环中每次都会计算一个假的当前时间。通过假的当前时间计算出日程的下次触发时间,然后计算下次日程的触发时间和假的当前时间的差值来决定线程挂起的时长。如何改变假的当前时间是通过changetime接口改变的。在这个api中会改变task.difftime的值,然后把全部线程全都唤醒,继续执行repeat循环,重新计算下次日程的触发时间,然后重新计算假的当时间和下次触发的时差=线程挂起的时长。如果改变的时刻在日程触发时刻的后面,要求改变时刻之前的日程全部触发,方案1和2都可以,如果提交了乐意日程触发时刻比现在真实的会见还靠前,则方案2不可行(不过这种情况一般不会有)

    作者:first_semon
             
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。如有问题,欢迎交流
  • 相关阅读:
    密码保护
    实现搜索功能
    完成个人中心—导航标签
    个人中心标签页导航
    评论列表显示及排序,个人中心显示
    完成评论功能
    从首页问答标题到问答详情页
    首页列表显示全部问答,完成问答详情页布局。
    JavaScript Array Reduce用于数组求和
    【Angular5】 返回前一页面 go back to previous page
  • 原文地址:https://www.cnblogs.com/first-semon/p/10620370.html
Copyright © 2011-2022 走看看