一、背景

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

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. JSP/Servlet Web 学习笔记 DayFour

    Servlet概述 Servelt是使用Java Servlet应用程序接口及相关类和方法的Java程序. Servlet是用Java编写的Server端程序,它与协议和平台无关.Servlet运行于 ...

  2. SQL Server 重新编译存储过程的方式有三种

    SQL Server 中,强制重新编译存储过程的方式有三种: sp_recompile 系统存储过程强制在下次执行存储过程时对其重新编译.具体方法是:从过程缓存中删除现有计划,强制在下次运行该过程时创 ...

  3. CSS使用示例

    CSS的存在就是将网页的内容与内容展示的方式进行了分离. 使用CSS的方式有好几种,最常用的是通过引入外部CSS文件进行使用 HTML <!DOCTYPE html> <html&g ...

  4. Android性能优化之避免内存泄漏的建议

    在android程序开发中,内存泄漏问题是比较常见的问题,相信有过一些android编程经历的程序猿都遇到过各种各样的内存泄漏.内存泄漏是造成应用程序OOM的主要原因之一,是编程中必须避免的问题.下面 ...

  5. nio的reactor模式

    转自:http://blog.csdn.net/it_man/article/details/38417761 线程状态转换图 就是非阻塞IO 采用多路分发方式举个例子吧,你服务器做一个聊天室,按照以 ...

  6. 堆栈(Stacks)

    堆栈(Stacks) 准备工作 安装Docker 1.13及以上版本 安装Docker Compose正如第三部分的准备工作. 安装Docker Machine正如第四部分的准备工作. 阅读第一部分的 ...

  7. 基站选址(base.c/cpp/pas)

    基站选址(base.c/cpp/pas) 题目描述  有N个村庄坐落在一条直线上,第i(i>1)个村庄距离第1个村庄的距离为Di.需要在这些村庄中建立不超过K个通讯基站,在第i个村庄建立基站的费 ...

  8. SSH整合一

    Spring整合Hibernate 1.引入我们所需的jar包 2.在applicationContext.xml中植入我们的数据源和sessionFactory工厂,将生成权交由Spring容器进行 ...

  9. 生活大爆炸版锤子剪刀布(NOIP2014)(真·模拟)

    水!水!!水!!!(重要的事情说三遍..) 1分钟代码题.. 原题传送门 这题啊,手打BOOL判断,然后乱搞啊.. 这有什么难的.. 加个快读就能拿第一啦.. 膜9018上各位大佬们.. 下面贴代码 ...

  10. 编写COOL编译器

    Coursera上面有Stanford的课程“Compilers”,该课程使用“龙书”作为参考书,并有一个编程项目,完成一个完整的编译器.这个编译器支持的语言称为COOL,是一个面向对象的用于教学的语 ...