zoukankan      html  css  js  c++  java
  • Lazy Scheduler:我的轻量级任务调度框架

    一、背景

           工作中经常涉及任务调度,一直都是采用while(true) => if hitted DO => Thread.Sleep(interval)的模式。但是最近实在是感觉这种实现模式很挫。并且没有考虑到性能问题,需要撞击n次才能命中一次,使用效率不足5%(一百次while循环命中不到5次),但是单方面加大线程睡眠时间又无法保证高准确性和高精度。那有么有其它好的思路:即可以保持高准确性、高精度,又不浪费资源呢?

     二、我的思路

          上述的短板在于:无目的的线程Sleep,如果我们可以每次恰到好处的Sleep,即线程被唤醒后刚好赶上下一次的任务到来,命中率就是100%了嘛。所以可以这样做:进入While后先按照Scheduler计算出下次的运行时间距离现在还有多久(Interval),然后直接Sleep(Interval),等待线程唤醒后就立即执行下一个既定Task就可以了。那这样做唯一的难点就在于你的Scheduler是否可计算、是否可以计算出下一次的运行时间点。

    还好,我碰到的逻辑都还是满足这一点需求的:

    (1)每隔一段时间执行一次的计划任务;

    (2)在指定时间点必须执行的计划任务;

    其他人性化设定:周六周日不运行。

     三、代码实现

    (1)主要有:负责调度的接口:IScheduler;Scheduler设定:ISchedulerSetting;任务接口:ITask以及一些其他的辅助类。

    (2)难点:计算Interval的实现类:FixTimeSchedulerSetting.cs和IntervalSchedulerSetting.cs

    //Author:      night-king
    // Email:       deepleo@163.com
    //Home:       http://deepleo.com
    //Github:     https://github.com/night-king/
    //Date:         2013-11-1 
    //Place:        Wuhan@China
    
    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Collections;
    
    namespace Deepleo.LazyScheduler.Setting
    {
        public class FixTimeSchedulerSetting : IFixTimeSchedulerSetting, IWeekSchedulerSetting
        {
            public IList<DayOfWeek> ExcludeWeeks
            {
                get;
                set;
            }
    
            public int Hour
            {
                get;
                set;
            }
    
            public int Minutes
            {
                get;
                set;
            }
    
            public int Second
            {
                get;
                set;
            }
    
            public FixTimeSchedulerSetting(IList<DayOfWeek> excludeWeeks)
            {
                ExcludeWeeks = excludeWeeks;
            }
    
            public virtual TimeSpan CalculateNext()
            {
                var nowDateTime = System.DateTime.Now;
                var expectNextTime = System.DateTime.Parse(string.Format("{0}-{1}-{2} {3}:{4}:{5}", nowDateTime.Year, nowDateTime.Month, nowDateTime.Day, Hour, Minutes, Second));
                var todayWeek = nowDateTime.DayOfWeek;
                var km = new WeekManager(ExcludeWeeks);
                var delayDays = km.CalculateDelayDays(todayWeek);
                if (delayDays == 0)// this day of week can do
                {
                    if (expectNextTime > nowDateTime) return expectNextTime - nowDateTime;
                    else delayDays++;
                }
                return expectNextTime.AddDays(delayDays) - nowDateTime;
            }
        }
    }
    

      

    using System;
    using System.Collections.Generic;
    using System.Text;
    
    namespace Deepleo.LazyScheduler.Setting
    {
        public class IntervalSchedulerSetting : IIntervalSchedulerSetting, IWeekSchedulerSetting
        {
    
            public TimeSpan Interval
            {
                get;
                set;
            }
    
            public IList<DayOfWeek> ExcludeWeeks
            {
                get;
                set;
            }
    
            public IntervalSchedulerSetting(IList<DayOfWeek> excludeWeeks)
            {
                ExcludeWeeks = excludeWeeks;
            }
    
            public TimeSpan CalculateNext()
            {
                var nowDateTime = System.DateTime.Now;
                var todayWeek =nowDateTime.DayOfWeek;
                var km = new WeekManager(ExcludeWeeks);
                var delayDays = km.CalculateDelayDays(todayWeek);
                var interval = Interval.Add(new TimeSpan(delayDays, 0, 0, 0));
                if (interval.CompareTo(new TimeSpan(0, 0, 1)) <= 0) return new TimeSpan(0, 0, 1);
                else return interval;
            }
        }
    }
    

    重要的辅助类:WeekManager的实现代码:

    //Author:      night-king
    // Email:       deepleo@163.com
    //Home:       http://deepleo.com
    //Github:     https://github.com/night-king/
    //Date:         2013-11-1 
    //Place:        Wuhan@China
    
    using System;
    using System.Collections.Generic;
    using System.Text;
    
    namespace Deepleo.LazyScheduler.Setting
    {
     
        public class WeekManager
        {
            private Dictionary<int, DayOfWeek> _allowWeekDict;
    
            public WeekManager(IList<DayOfWeek> notAllowWeeks)
            {
                _allowWeekDict = new Dictionary<int, DayOfWeek>();
                if (!notAllowWeeks.Contains(DayOfWeek.Sunday))
                    _allowWeekDict.Add(0, DayOfWeek.Sunday);
                if (!notAllowWeeks.Contains(DayOfWeek.Monday))
                    _allowWeekDict.Add(1, DayOfWeek.Monday);
                if (!notAllowWeeks.Contains(DayOfWeek.Tuesday))
                    _allowWeekDict.Add(2, DayOfWeek.Tuesday);
                if (!notAllowWeeks.Contains(DayOfWeek.Wednesday))
                    _allowWeekDict.Add(3, DayOfWeek.Wednesday);
                if (!notAllowWeeks.Contains(DayOfWeek.Thursday))
                    _allowWeekDict.Add(4, DayOfWeek.Thursday);
                if (!notAllowWeeks.Contains(DayOfWeek.Friday))
                    _allowWeekDict.Add(5, DayOfWeek.Friday);
                if (!notAllowWeeks.Contains(DayOfWeek.Saturday))
                    _allowWeekDict.Add(6, DayOfWeek.Saturday);
            }
    
            /// <summary>
            /// Calcute how many delay days
            /// </summary>
            /// <param name="week">current day of week</param>
            /// <returns>delay days</returns>
            public int CalculateDelayDays(DayOfWeek week)
            {
                var weekOfDay = (int)week;
                int distence = 0;
                while (true)
                {
                    if (_allowWeekDict.ContainsKey(weekOfDay))
                    {
                        return distence;
                    }
                    else
                    {
                        weekOfDay = weekOfDay < 6 ? weekOfDay + 1 : 0;
                        distence++;
                    }
                }
            }
        }
    }
    

    四、测试

    (1)5s钟时间间隔的测试结果:

    (2)1s测试结果:

    再看CPU占用情况: 

    基本上稳定在0%,内存占用也只有6.4k.

    五、代码下载:

    http://files.cnblogs.com/deepleo/SchedulerSolution.zip

    https://github.com/night-king/LazyScheduler

  • 相关阅读:
    bzoj3505 数三角形 组合计数
    cogs2057 殉国 扩展欧几里得
    cogs333 荒岛野人 扩展欧几里得
    bzoj1123 BLO tarjan求点双连通分量
    poj3352 road construction tarjan求双连通分量
    cogs1804 联合权值 dp
    cogs2478 简单的最近公共祖先 树形dp
    cogs1493 递推关系 矩阵
    cogs2557 天天爱跑步 LCA
    hdu4738 Caocao's Bridge Tarjan求割边
  • 原文地址:https://www.cnblogs.com/deepleo/p/LazyScheduler.html
Copyright © 2011-2022 走看看