zoukankan      html  css  js  c++  java
  • 定时任务的处理

          对于定时任务,一般由时间戳Timers 或者死循环While(true) 操作,两者都能达到,指定间隔时间内执行去执行任务,这里不做效率的比较,只说明一下适合的场景。先拿while来说,执行完成任务后,设置好线程等待时间即可,它有一优势,即如果此次任务未执行完,则不会进入下一次,也就是说是可控的,不会同时执行两笔相同任务

            public void StartLoadTask()
            {
                while (true)
                {
                    //... 业务逻辑//等待60秒,进入下一次
                    Thread.Sleep(60000);
                }
            }

    再来看一看Times ,这里仅作 System.Timers 下的timer的说明(非 Threading 中的timer),如下图

     //执行定时服务  
     var timer = new Timer() { AutoReset = true, Enabled = true, Interval=60000 };
     timer.Elapsed += (sender, eventArgs) => Helper.StartTask();

    可以满足每隔60s 调用一次 StartTask 方法,但是会有一个问题,试想如果由于某个内部或外部原因,导致执行一次程序的时间超过了60s,如果直接这样写,则会出现第一个任务还未执行完,下一个任务又进来,则同时运行两笔任务的情况,显然是不可取的,需要进行改进,即需等上次任务执行完,再去等待间隔,然后进入下一次任务,否则永远要等上一笔任务执行完。这里将 timer 当做参数 传递给 StartTask 方法,则

            public void StartTask(Timer timer)
            {
                timer.Stop();            
                //... 业务逻辑
                timer.Start();
    
            }

    看似两种操作都达到了需求,细想下来,还有不妥。试想任务是每分钟执行一次的,虽然这样处理解决了不会同时执行多笔任务的问题,可若任务执行时间超过了60s,则错过了下一次任务的执行时间。这样的话岂不是顾此失彼,既要每次只执行一笔任务,又不能错过每一次任务。想要满足这种要求,则只能引用安全队列机制,每隔60s,便把任务写入队列中,再启一个线程去循环读取队列里的任务便可。这样一个线程尽管往里面写,另外一个线程负责取,每执行完一笔任务,就去读下一笔任务,如此往复。

    写入队列如下

            public void StartTask()
            {
                //任务t
                //写入任务队列              
                TaskQueue.Enqueue(t);
                LogHelper.LogQueue.Enqueue("写入报告任务:" + t.Date);
            }

    取出队列如下

            public void StartTask()
            {
                while (true)
                {
                    if (!TaskQueue.IsEmpty)
                    {
                        //取出任务
                        TaskQueue.TryDequeue(out ICCTask task);
                        LogHelper.LogQueue.Enqueue("取出报告任务:" + task.Date);
                        //执行任务 逻辑
                        // ...
                    }
                    Thread.Sleep(60000);
                }
            }

    当然取出队列任务 需要设置线程为 异步  Task.Factory.StartNew(StartTask);

  • 相关阅读:
    抛开BlazeDS,自定义flex RPC
    设计模式学习03装饰器模式
    通过ANT生成MANIFEST.MF中的ClassPath属性
    Spring JDBCTemplate与Hiberante混用
    关于 两个 datetime 列的差别导致了运行时溢出
    在Wcf中使用Nhibernate (续)
    sql2005/sql2008 分页
    工行支付api查询asp.net C# 实现
    生成静态页面的vbscript
    Asp.net Mvc Post ID Bug
  • 原文地址:https://www.cnblogs.com/Sientuo/p/12012026.html
Copyright © 2011-2022 走看看