一、背景

工作中经常涉及任务调度,一直都是采用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

  1. //Author: night-king
  2. // Email: deepleo@163.com
  3. //Home: http://deepleo.com
  4. //Github: https://github.com/night-king/
  5. //Date: 2013-11-1
  6. //Place: Wuhan@China
  7.  
  8. using System;
  9. using System.Collections.Generic;
  10. using System.Text;
  11. using System.Collections;
  12.  
  13. namespace Deepleo.LazyScheduler.Setting
  14. {
  15. public class FixTimeSchedulerSetting : IFixTimeSchedulerSetting, IWeekSchedulerSetting
  16. {
  17. public IList<DayOfWeek> ExcludeWeeks
  18. {
  19. get;
  20. set;
  21. }
  22.  
  23. public int Hour
  24. {
  25. get;
  26. set;
  27. }
  28.  
  29. public int Minutes
  30. {
  31. get;
  32. set;
  33. }
  34.  
  35. public int Second
  36. {
  37. get;
  38. set;
  39. }
  40.  
  41. public FixTimeSchedulerSetting(IList<DayOfWeek> excludeWeeks)
  42. {
  43. ExcludeWeeks = excludeWeeks;
  44. }
  45.  
  46. public virtual TimeSpan CalculateNext()
  47. {
  48. var nowDateTime = System.DateTime.Now;
  49. var expectNextTime = System.DateTime.Parse(string.Format("{0}-{1}-{2} {3}:{4}:{5}", nowDateTime.Year, nowDateTime.Month, nowDateTime.Day, Hour, Minutes, Second));
  50. var todayWeek = nowDateTime.DayOfWeek;
  51. var km = new WeekManager(ExcludeWeeks);
  52. var delayDays = km.CalculateDelayDays(todayWeek);
  53. if (delayDays == 0)// this day of week can do
  54. {
  55. if (expectNextTime > nowDateTime) return expectNextTime - nowDateTime;
  56. else delayDays++;
  57. }
  58. return expectNextTime.AddDays(delayDays) - nowDateTime;
  59. }
  60. }
  61. }

  

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4.  
  5. namespace Deepleo.LazyScheduler.Setting
  6. {
  7. public class IntervalSchedulerSetting : IIntervalSchedulerSetting, IWeekSchedulerSetting
  8. {
  9.  
  10. public TimeSpan Interval
  11. {
  12. get;
  13. set;
  14. }
  15.  
  16. public IList<DayOfWeek> ExcludeWeeks
  17. {
  18. get;
  19. set;
  20. }
  21.  
  22. public IntervalSchedulerSetting(IList<DayOfWeek> excludeWeeks)
  23. {
  24. ExcludeWeeks = excludeWeeks;
  25. }
  26.  
  27. public TimeSpan CalculateNext()
  28. {
  29. var nowDateTime = System.DateTime.Now;
  30. var todayWeek =nowDateTime.DayOfWeek;
  31. var km = new WeekManager(ExcludeWeeks);
  32. var delayDays = km.CalculateDelayDays(todayWeek);
  33. var interval = Interval.Add(new TimeSpan(delayDays, 0, 0, 0));
  34. if (interval.CompareTo(new TimeSpan(0, 0, 1)) <= 0) return new TimeSpan(0, 0, 1);
  35. else return interval;
  36. }
  37. }
  38. }

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

  1. //Author: night-king
  2. // Email: deepleo@163.com
  3. //Home: http://deepleo.com
  4. //Github: https://github.com/night-king/
  5. //Date: 2013-11-1
  6. //Place: Wuhan@China
  7.  
  8. using System;
  9. using System.Collections.Generic;
  10. using System.Text;
  11.  
  12. namespace Deepleo.LazyScheduler.Setting
  13. {
  14.  
  15. public class WeekManager
  16. {
  17. private Dictionary<int, DayOfWeek> _allowWeekDict;
  18.  
  19. public WeekManager(IList<DayOfWeek> notAllowWeeks)
  20. {
  21. _allowWeekDict = new Dictionary<int, DayOfWeek>();
  22. if (!notAllowWeeks.Contains(DayOfWeek.Sunday))
  23. _allowWeekDict.Add(0, DayOfWeek.Sunday);
  24. if (!notAllowWeeks.Contains(DayOfWeek.Monday))
  25. _allowWeekDict.Add(1, DayOfWeek.Monday);
  26. if (!notAllowWeeks.Contains(DayOfWeek.Tuesday))
  27. _allowWeekDict.Add(2, DayOfWeek.Tuesday);
  28. if (!notAllowWeeks.Contains(DayOfWeek.Wednesday))
  29. _allowWeekDict.Add(3, DayOfWeek.Wednesday);
  30. if (!notAllowWeeks.Contains(DayOfWeek.Thursday))
  31. _allowWeekDict.Add(4, DayOfWeek.Thursday);
  32. if (!notAllowWeeks.Contains(DayOfWeek.Friday))
  33. _allowWeekDict.Add(5, DayOfWeek.Friday);
  34. if (!notAllowWeeks.Contains(DayOfWeek.Saturday))
  35. _allowWeekDict.Add(6, DayOfWeek.Saturday);
  36. }
  37.  
  38. /// <summary>
  39. /// Calcute how many delay days
  40. /// </summary>
  41. /// <param name="week">current day of week</param>
  42. /// <returns>delay days</returns>
  43. public int CalculateDelayDays(DayOfWeek week)
  44. {
  45. var weekOfDay = (int)week;
  46. int distence = 0;
  47. while (true)
  48. {
  49. if (_allowWeekDict.ContainsKey(weekOfDay))
  50. {
  51. return distence;
  52. }
  53. else
  54. {
  55. weekOfDay = weekOfDay < 6 ? weekOfDay + 1 : 0;
  56. distence++;
  57. }
  58. }
  59. }
  60. }
  61. }

四、测试

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

(2)1s测试结果:

再看CPU占用情况:

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

五、代码下载:

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

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

Lazy Scheduler:我的轻量级任务调度框架的更多相关文章

  1. Lazy Scheduler

    Lazy Scheduler:我的轻量级任务调度框架   一.背景 工作中经常涉及任务调度,一直都是采用while(true) => if hitted DO => Thread.Slee ...

  2. SpringBoot官方支持任务调度框架,轻量级用起来也挺香!

    大家好,我是二哥呀.定时任务的应用场景其实蛮常见的,比如说: 数据备份 订单未支付则自动取消 定时爬取数据 定时推送信息 定时发布文章 等等(想不出来了,只能等等来凑,,反正只要等的都需要定时,怎么样 ...

  3. 企业级任务调度框架Quartz(6) 任务调度器(Scheduler)

    前序:      我们已经在前面的内容能里看到了,我们用 Scheduler 来管理我们的 Job:创建并关联触发器以使 Job 能被触发执行:以及如可选择 calendar 为给定的时程安排提供更多 ...

  4. Java任务调度框架Quartz入门

    Quartz[kwɔːts]:石英,其框架和名字一样简单朴素又不失魅力,在Java程序界,Quartz大名鼎鼎,很多Java应用几乎都集成或构建了一个定时任务调度系统,Quartz是一个定时任务调度框 ...

  5. APScheduler轻量级定时任务框架

    目录 一.APScheduler简介 支持的后端存储作业 集成的Python框架 二.APScheduler下载安装 三.APScheduler组件 各组件简介 调度器 作业存储器 执行器 触发器 四 ...

  6. Quarzt.NET 任务调度框架

      Quartz.NET是一个开源的作业调度框架,是 OpenSymphony 的 Quartz API 的.NET移植,它用C#写成,可用于winform和asp.net应用中.它提供了巨大的灵活性 ...

  7. Quartz:不要重复造轮子,一款企业级任务调度框架。

    背景 第一次遇到定时执行某些任务的需求时,很多朋友可能设计了一个小类库,这个类图提高了一个接口,然后由调度器调度所有注册的接口类型,我就是其中之一,随着接触的开源项目越来越多,我的某些开发习惯受到了影 ...

  8. 企业级任务调度框架Quartz(8) 线程在Quartz里的意义(2)

    前序:      做为企业里的任务调度框架,出现同一时间点同时运行两个任务,或者两个任务因为开始的执行时间和执行时间的长短,很有可能出现任务并发执行的情况:因为Quartz的实现是采用java编程,那 ...

  9. 企业级任务调度框架Quartz(3) 一个简单的Quartz 例子

    1. 一个简单的Quartz 工程     本示例应用比起众所周知的 System.out.println("Hello world from Quartz") 来还是要有趣些.当 ...

随机推荐

  1. hdu2010(dfs+剪枝)

    Tempter of the Bone Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Othe ...

  2. asp+access win2008php+mysql /dedecms 配置总结

    1.  IIS 应用池  高级设置  启用32位应用程序:True 2. c盘window/Temp user 应该有管理权限           如果不行 creator owner 给予修改权限 ...

  3. Windows域同步检查repadmin

    C:\Users\>repadmin /show replUsage: repadmin <cmd> <args> [/u:{domain\user}] [/pw:{pa ...

  4. css去掉点击连接时所产生的虚线边框技巧兼容符合w3c标准的浏览器

    解决方法: 1.在css中加上outline:none; 代码如下: a.fontnav { text-align:left;color:#555; text-decoration:none; out ...

  5. 飞镖(bzoj 2335)

    Description 飞镖是在欧洲颇为流行的一项运动.它的镖盘上分为20个扇形区域,分别标有1到20的分值,每个区域中有单倍.双倍和三倍的区域,打中对应的区域会得到分值乘以倍数所对应的分数.例如打中 ...

  6. Handler 源码分析

    Handler用法: 无参 Handler 构造函数实例化一个 Handler 类型的全局变量,并重写其 handleMessage 方法,在某一方法内调用 Handler 的 sendEmptyMe ...

  7. 自己写的enum转换的一个扩展,

    public static String ToEnumName(this int? source, Type e) { if (!source.HasValue) throw new Argument ...

  8. 行为型设计模式之策略模式(Strategy)

    结构 意图 定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换.本模式使得算法可独立于使用它的客户而变化. 适用性 许多相关的类仅仅是行为有异.“策略”提供了一种用多个行为中的一个行为来配 ...

  9. error LNK2001: unresolved external symbol "int g_cTemplates" (?g_cTemplates@@3HA)(转)

    原文转自:http://blog.sina.com.cn/s/blog_639a2ad70101kpen.html 编译directshow若干问题的解决 1.安装好windows sdk,进入dir ...

  10. http模拟登录

    = =其实很简单,写这个的目的呢,是为了练习下Ruby而已 就是post到登录地址,得到cookie,然后以后的请求都用这个cookie就好了. require 'net/http' module E ...