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. win7通过配置怎么样ODBC数据源

    我的系统是win7最终.找了半天也没有找到控制面板上的卷管理工具--数据源.后来在网上搜索后发现win7事实并非如此开放ODBC数据源管理,打开ODBC数据源管理方法是cmd输入命令框odbcad32 ...

  2. (一)spring MVC基本概念和流程

    MVC的概念 Model(模型):包含数据和行为.不过现在一般都分离开来:Value Object(数据) 和 服务层(行为). View(视图):负责进行模型的展示,一般就是展示给用户的界面. Co ...

  3. 【百度地图API】如何制作公交线路的搜索?如331路

    原文:[百度地图API]如何制作公交线路的搜索?如331路 摘要: 从A点到B点的公交导航大家都知道怎么做了,那么单独查询331路公交车的公交路线,如何制作呢?我们一起来学习一下~ --------- ...

  4. Cocos2d-android游戏引擎-介绍

    一.游戏引擎概念 什么是游戏引擎       游戏引擎是指一些已编写好的可编辑游戏系统或者一些交互式实时图像应用程序的核心组件.这些系统为游戏设计者提供各种编写游戏所需的各种工具,其目的在于让游戏设计 ...

  5. 蜗牛—Hibernate之初识配置

    下载Hibernate的jar包 把下面jar文件考到项目lib下 然后在myeclipse中打开database的view视图创建一个新的数据库连接 接下来,配置连接,须要导入ORACLE的jar包 ...

  6. mysql5.6.16绿色版配置、运行

    原文:mysql5.6.16绿色版配置.运行 1.从该地址http://dev.mysql.com/downloads/mysql/中选择windows的版本,选择下载. 2.将下载的压缩包解压. 3 ...

  7. hibernate的orphanRemoval

    在@OneToMany与@OneToOne中使用orphanRemoval = true时候 改动保存时候setXXX org.springframework.orm.hibernate3.Hiber ...

  8. VS2015预览

    VS2015预览版体验   .NET开源了,JAVA颤抖吧...据说VS2015可以开发android,ios,wp应用程序了,还可以开发能运行在mac,linux上的ASP.NET网站,如果真是这样 ...

  9. Spring之SpringMVC的Controller(源码)分析

    说明: 例子就不举了,还是直接进入主题,本文主要是以SpringMVC的Controller接口为入点,来分析SpringMVC中C的具体实现和处理过程. 1.Controller接口 public ...

  10. swift 笔记 (二十) —— 泛型

    泛型 泛型是为了解决在针对不同数据类型.而做了同一种功能的操作导致的每一个类型我们都要写一份代码的问题. 有了泛型,我们能够仅仅写一份逻辑代码,而适应于不同的数据类型. func swapInt(in ...