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. DDD实践案例:引入事件驱动与中间件机制来实现后台管理功能

    DDD实践案例:引入事件驱动与中间件机制来实现后台管理功能 一.引言 在当前的电子商务平台中,用户下完订单之后,然后店家会在后台看到客户下的订单,然后店家可以对客户的订单进行发货操作.此时客户会在自己 ...

  2. Android 自己的自动化测试(5)&lt;robotium&gt;

    大约Android自己的自动化测试UI测试,前出台Android 自己主动化測试(4)<uiautomator>, 在android原生的单元測试框架上,利用uiautomator.jar ...

  3. Objective-C马路成魔【12-分类和协议】

    郝萌主倾心贡献.尊重作者的劳动成果,请勿转载. 假设文章对您有所帮助.欢迎给作者捐赠,支持郝萌主.捐赠数额任意,重在心意^_^ 我要捐赠: 点击捐赠 Cocos2d-X源代码下载:点我传送 分类与协议 ...

  4. Swift中文教程(一)--欢迎来到Swift的世界

    原文:Swift中文教程(一)--欢迎来到Swift的世界 Apple凌晨时在WWDC发布了Swift编程语言,语法简介我很喜欢,市面上没有完整的中文教程,我在ibooks里面下载了英文原版,现在开始 ...

  5. RHEL5 X86-64上安装Oracle 11gR2演示样例与总结

    进入Oracle DBA行业也有好几年了,可是说到安装Oracle的经验,我还真不是特别多,印象中刚開始每次安装都有点磕磕碰碰,随着接触Oracle的时间越来越长,各方面的原理.机制也都有一定的了解后 ...

  6. LogMaster4Net

    使用LogMaster4Net实现应用程序日志的集中管理 日志在软件系统中的重要性我在此也不赘述了,几乎所有程序员每天都会更日志打交道. 那么你是否曾今为这样的一些事情而困扰过: - 远程登录到不同的 ...

  7. 【百度地图API】如何制作自定义样式的公交导航结果面板?

    原文:[百度地图API]如何制作自定义样式的公交导航结果面板? 摘要: 百度地图API有默认的公交导航结果面板,但样式比较单一:而百度地图上的结果面板就比较美观.如何利用百度地图API来制作一个比较美 ...

  8. 在Windows系统中安装集成的PHP开发环境

    原文:在Windows系统中安装集成的PHP开发环境 刚想学php的,又不会配置复杂php的环境,可以使用集成的,目前网上提供常用的PHP集成环境主要有AppServ.phpStudy.WAMP和XA ...

  9. C# foreach 有用方法具体解释

    网上查资料,说foreach 不能改动迭代变量,仅仅能訪问迭代变量.自己理解也不是非常深,通过几个代码进行验证,发现foreach的使用方法还有点特别 验证方法: 1. 迭代变量 为int int[] ...

  10. Linux学习笔记——怎样在交叉编译时使用共享库

    0.前言     在较为复杂的项目中会利用到交叉编译得到的共享库(*.so文件).在这样的情况下便会产生下面疑问,比如:     [1]交叉编译时的共享库是否须要放置于目标板中,假设须要放置在哪个文件 ...