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
//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:我的轻量级任务调度框架的更多相关文章
- Lazy Scheduler
Lazy Scheduler:我的轻量级任务调度框架 一.背景 工作中经常涉及任务调度,一直都是采用while(true) => if hitted DO => Thread.Slee ...
- SpringBoot官方支持任务调度框架,轻量级用起来也挺香!
大家好,我是二哥呀.定时任务的应用场景其实蛮常见的,比如说: 数据备份 订单未支付则自动取消 定时爬取数据 定时推送信息 定时发布文章 等等(想不出来了,只能等等来凑,,反正只要等的都需要定时,怎么样 ...
- 企业级任务调度框架Quartz(6) 任务调度器(Scheduler)
前序: 我们已经在前面的内容能里看到了,我们用 Scheduler 来管理我们的 Job:创建并关联触发器以使 Job 能被触发执行:以及如可选择 calendar 为给定的时程安排提供更多 ...
- Java任务调度框架Quartz入门
Quartz[kwɔːts]:石英,其框架和名字一样简单朴素又不失魅力,在Java程序界,Quartz大名鼎鼎,很多Java应用几乎都集成或构建了一个定时任务调度系统,Quartz是一个定时任务调度框 ...
- APScheduler轻量级定时任务框架
目录 一.APScheduler简介 支持的后端存储作业 集成的Python框架 二.APScheduler下载安装 三.APScheduler组件 各组件简介 调度器 作业存储器 执行器 触发器 四 ...
- Quarzt.NET 任务调度框架
Quartz.NET是一个开源的作业调度框架,是 OpenSymphony 的 Quartz API 的.NET移植,它用C#写成,可用于winform和asp.net应用中.它提供了巨大的灵活性 ...
- Quartz:不要重复造轮子,一款企业级任务调度框架。
背景 第一次遇到定时执行某些任务的需求时,很多朋友可能设计了一个小类库,这个类图提高了一个接口,然后由调度器调度所有注册的接口类型,我就是其中之一,随着接触的开源项目越来越多,我的某些开发习惯受到了影 ...
- 企业级任务调度框架Quartz(8) 线程在Quartz里的意义(2)
前序: 做为企业里的任务调度框架,出现同一时间点同时运行两个任务,或者两个任务因为开始的执行时间和执行时间的长短,很有可能出现任务并发执行的情况:因为Quartz的实现是采用java编程,那 ...
- 企业级任务调度框架Quartz(3) 一个简单的Quartz 例子
1. 一个简单的Quartz 工程 本示例应用比起众所周知的 System.out.println("Hello world from Quartz") 来还是要有趣些.当 ...
随机推荐
- spring 配置问题记录1-@ResponseBody和favorPathExtension
在搭建springmvc+easyui的项目时,有一个地方参照网上说的方法一直没实现出来, 就是前台的datagrid的数据渲染不上去, 尝试了好多种方法,包括也找了目前手里的项目来进行比较,也没发现 ...
- ocrosoft Contest1316 - 信奥编程之路~~~~~第三关 问题 J: 外币兑换
http://acm.ocrosoft.com/problem.php?cid=1316&pid=9 题目描述 小明刚从美国回来,发现手上还有一些未用完的美金,于是想去银行兑换成人民币.可是听 ...
- nf_register_hooks解读
nf_register_hooks是什么 net->netns_nf->nf_hook_entry[NFPROTO_NUMPROTO][NF_MAX_HOOKS=8] (nf) ...
- jquerydom对象和字符串之间的转换
字符串转jquery对象:var tmp = $('<div>dd</div>').attr('id','bbq'); //用$符包裹起来即可 jquery对象转字符串: tm ...
- [LA_3938]最大连续动态和
Sample Input 3 1 1 2 3 1 1 Sample Output Case 1: 1 1 线段树 L,R表示该区间的左右端点,sum表示该区间值的总和 l,r表示该区间连续的最大和的左 ...
- 割点与桥,强连通分量,点双,边双[poj_1236]学校网络
割点与桥 题目描述 给定一张无向图G(V,E),你需要找出所有的割点与桥. 输入 第一行给出两个正整数V,E. 接下来E行每行两个正整数x,y,表示有一条连接x,y的边. 输出 输出共2行,第一行输出 ...
- Andriod布局
布局[ViewGroup] 像素单位的变化:是用dip,而不是px,主要用于宽高的设置 在Android中支持的描述大小区域的类型有以下几种. px(pixels)——像素:不同的设备显示效果相同 ...
- linux内核情景分析之execve()
用来描述用户态的cpu寄存器在内核栈中保存情况.可以获取用户空间的信息 struct pt_regs { long ebx; //可执行文件路径的指针(regs.ebx中 long ecx; //命令 ...
- /proc/sys/shm/drop_caches
author:skate time:2012/02/22 手工释放linux内存--/proc/sys/vm/drop_cache 转载一篇文章 linux的内存查看: [root@localhost ...
- python 删除字符串中的连续空格只保留一个
目标是要去掉多余的空格字符,在相邻字符串中,只保留一个空格 紫梧桐 - 蛋壳公寓朝阳门店 郑田力 可以利 ...