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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
//Author:      night-king
// Email:       deepleo@163.com
//Home:       http://deepleo.com
//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;
        }
    }
}

  

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
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的实现代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
//Author:      night-king
// Email:       deepleo@163.com
//Home:       http://deepleo.com
//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

Lazy Scheduler的更多相关文章

  1. Lazy Scheduler:我的轻量级任务调度框架

    一.背景 工作中经常涉及任务调度,一直都是采用while(true) => if hitted DO => Thread.Sleep(interval)的模式.但是最近实在是感觉这种实现模 ...

  2. AndroidStudio3.0无法打开Android Device Monitor的解决办法(An error has occurred on Android Device Monitor)

    ---恢复内容开始--- 打开monitor时出现 An error has occurred. See the log file... ------------------------------- ...

  3. 代码的坏味道(15)——冗余类(Lazy Class)

    坏味道--冗余类(Lazy Class) 特征 理解和维护类总是费时费力的.如果一个类不值得你花费精力,它就应该被删除. 问题原因 也许一个类的初始设计是一个功能完全的类,然而随着代码的变迁,变得没什 ...

  4. Mach-O 的动态链接(Lazy Bind 机制)

    ➠更多技术干货请戳:听云博客 动态链接 要解决空间浪费和更新困难这两个问题最简单的方法就是把程序的模块相互分割开来,形成独立的文件,而不再将它们静态的链接在一起.简单地讲,就是不对那些组成程序的目标文 ...

  5. 从scheduler is shutted down看程序员的英文水平

    我有个windows服务程序,今天重点在测试系统逻辑.部署后,在看系统日志时,不经意看到一行:scheduler is shutted down. 2016-12-29 09:40:24.175 {& ...

  6. Spring 4 + Quartz 2.2.1 Scheduler Integration Example

    In this post we will see how to schedule Jobs using Quartz Scheduler with Spring. Spring provides co ...

  7. VMware中CPU分配不合理以及License限制引起的SQL Scheduler不能用于查询处理

    有一台SQL Server(SQL Server 2014 标准版)服务器中的scheduler_count与cpu_count不一致,如下截图所示: SELECT  cpu_count ,      ...

  8. Lazy Load, 延迟加载图片的 jQuery 插件.

    Lazy Load 是一个用 JavaScript 编写的 jQuery 插件. 它可以延迟加载长页面中的图片. 在浏览器可视区域外的图片不会被载入, 直到用户将页面滚动到它们所在的位置. 这与图片预 ...

  9. Hibernate之lazy延迟加载

    一.延迟加载的概念 当Hibernate从数据库中加载某个对象时,不加载关联的对象,而只是生成了代理对象,获取使用session中的load的方法(在没有改变lazy属性为false的情况下)获取到的 ...

随机推荐

  1. ASP.NET MVC+EF框架+EasyUI实现权限管理系列(14)-主框架搭建

    原文:ASP.NET MVC+EF框架+EasyUI实现权限管理系列(14)-主框架搭建    ASP.NET MVC+EF框架+EasyUI实现权限管系列 (开篇)   (1):框架搭建    (2 ...

  2. Tomcat剖析(四):Tomcat默认连接器(2)

    Tomcat剖析(四):Tomcat默认连接器(2) 1. Tomcat剖析(一):一个简单的Web服务器 2. Tomcat剖析(二):一个简单的Servlet服务器 3. Tomcat剖析(三): ...

  3. 私人定制javascript中函数小知识点

    函数的定义 首先在javascript中,函数就是对象,程序可以随意操控它们.比如,可以给它们设置属性,甚至调用它们的方法.函数使用function关键字来定义.它既可以用在函数定义表达式,也可以用在 ...

  4. Windows Phone 8.1 多媒体(3):音乐

    原文:Windows Phone 8.1 多媒体(3):音乐 Windows Phone 8.1 多媒体(1):相片 Windows Phone 8.1 多媒体(2):视频 Windows Phone ...

  5. JAVA进阶-注解

    注解元数据分为4部分分别为Target,Documented,Inherited,Retention: Target>指定被注解的注解仅仅能使用在某个类型上;ElementType指定其类型:能 ...

  6. 微软不也是从Altair Basic这丑小鸭长成白天鹅吗?

    微软不也是从Altair Basic这丑小鸭长成白天鹅吗? February 2015 如果你想要弄清楚初创企业是怎么一回事的话,其中一个非常有价值的尝试是去研究下那些获得巨大成功的公司,去分析下为什 ...

  7. 一步一步写算法(之prim算法 下)

    原文:一步一步写算法(之prim算法 下) [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 前两篇博客我们讨论了prim最小生成树的算法,熟悉 ...

  8. ubuntu eclipse android搭建

    1.eclipse加入android adt: 终端:sudo gedit /etc/hosts 加入: #for android 173.194.72.93 dl.google.com 173.19 ...

  9. Android KitCat 4.4.2 ADB 官方所支持的所有Services格式翻译

    在之前的文章中有转帖网上同行制作的ADB协议表格<<adb概览及协议参考>>,但不够详尽,所以这里自己另外基于Android 4.4.2的技术文档重新做一次翻译. HOST S ...

  10. CORS(跨域资源共享)跨域问题及解决

    当使用ajax跨域请求时,浏览器报错:XmlHttpRequest error: Origin null is not allowed by Access-Control-Allow-Origin.肯 ...