我想在特定时间调用我的C#应用程序上的特定功能。首先我考虑使用Timer
(System.Time.Timer)
,但很快就无法使用使用。为什么呢?
简单。 Timer类需要Interval
毫秒,但考虑到我可能希望执行该函数,让我们在一周之内说:
现在让我们记住,Interval
接受的数据类型为int
,我们知道int
范围从-2,147,483,648到2,147,483,647。
这会使Timer
无效,不是在这种情况下,但是在超过25天的情况下,一旦我们无法设置Interval
大于2,147,483,647毫秒。
所以我需要一个解决方案,我可以指定何时应该调用该函数。 像这样:
solution.ExecuteAt = "30-04-2010 15:10:00";
solution.Function = "functionName";
solution.Start();
因此,当系统时间到达“30-04-2010 15:10:00”时,该功能将在应用程序中执行。
如何解决这个问题?
其他信息:这些功能将起什么作用?
修改
似乎Interval
接受的数据类型为double
,但是如果您设置的值大于int
到Interval
,并调用{{1}它抛出异常Start()
。
编辑2:
JørnSchou-Rode建议使用Ncron来处理调度任务,起初看起来这似乎是一个很好的解决方案,但我想听听一些使用它的人。
答案 0 :(得分:12)
你的“Start()”方法应该产生一个以定义的间隔唤醒的线程,检查时间,如果你没有达到所需的时间,则回到睡眠状态。
答案 1 :(得分:11)
我建议您只编写一个处理其业务部分的程序,然后在必要时使用 Windows任务计划程序执行该程序。
答案 2 :(得分:10)
任务调度的一种方法,与klausbyskov提出的方法相似,就是在现有的.NET调度框架/库之上构建调度服务。与使用Windows任务计划程序相比,这具有以下优点:(a)允许在同一项目中定义多个作业,以及(b)将作业和调度逻辑“保持在一起” - 即不依赖于容易丢失的服务器设置系统升级/更换。
我知道有两个提供此类功能的开源项目:
“Quartz.NET是一个功能齐全的开源作业调度系统,可用于从最小的应用程序到大型企业系统。”我自己从来没有真正使用过这个框架,但是通过研究网站,我给人的印象是一个非常可靠的工具,提供了许多很酷的功能。 Stackoverflow上有[quartz-net]
标记的事实也可能表明它实际上是在野外使用。
“NCron是一个轻量级的库,用于在.NET服务器平台上构建和部署预定的后台作业。”它没有Quartz.NET多一半的功能,并且它在Stackoverflow上没有任何标签,但是作者(你们真的)认为它的低摩擦API使它更容易上手。
在NCron之上构建您的计划服务,您可以使用一行代码安排CleanupJob
每周执行:
service.Weekly().Run<CleanupJob>();
好的,你需要大约三行样板代码来实际将你的项目变成一个Windows服务,但是当我声称它可以用一行代码完成时听起来更令人印象深刻;)子>
答案 3 :(得分:3)
你可以为一个带有DateTime实例的Timer编写某种包装类。然后执行以下步骤:
在某个时候,差异将小于Interval属性的最大允许值,然后您可以在包装器中触发一个最终调用所需方法的事件。
答案 4 :(得分:3)
使用System.Threading.Timer:
var timer = new System.Threading.Timer(delegate { }, // Pass here a delegate to the method
null,
TimeSpan.FromDays(7), // Execute Method after 7 days.
TimeSpan.Zero);
答案 5 :(得分:0)
你可以使用System.Threading.Timer
类,它提供一个接受表示为Int64的区间的构造函数,它应该足以满足你的需要。
现在换其他东西:
Process
课程开始/停止/配置程序(我实际上并没有得到您所谓的“自定义命令”)答案 6 :(得分:0)
班级System.Threading.Timer
也有同样的限制(根据MSDN会抛出ArgumentOutOfRangeException
。)
似乎没有.Net Framework类本身能够绕过Int32.MaxValue
毫秒上限。
public static class Scheduler
{
private const long TimerGranularity = 100;
static Scheduler()
{
ScheduleTimer = new Timer(Callback, null, Timeout.Infinite, Timeout.Infinite);
Tasks = new SortedQueue<Task>();
}
private static void Callback(object state)
{
var first = Tasks.Peek();
if(first.ExecuteAt<DateTime.Now)
{
Tasks.Dequeue();
var executionThread = new Thread(() => first.Function());
executionThread.Start();
}
}
private static Timer ScheduleTimer { get; set; }
public static void Start()
{
ScheduleTimer.Change(0, TimerGranularity);
}
public static void Add(Task task)
{
Tasks.Enqueue(task);
}
public static SortedQueue<Task> Tasks { get; set; }
}
public class Task : IComparable<Task>
{
public Func<Boolean> Function { get; set; }
public DateTime ExecuteAt { get; set; }
public int CompareTo(Task other)
{
return ExecuteAt.CompareTo(other.ExecuteAt);
}
}
我使用的解决方案类似于上面的示例:管理所有Scheduler
的类Task
(为了避免为我们要安排的每个任务设置计时器)。
任务被添加到能够执行排序插入的队列中。请注意,SortedQueue<T>
不是.Net Framework的一种类型,而是一种假设的,易于编码的集合,能够在类似的类型T上对插入进行排序。
调度程序每隔TimerGranularity
毫秒唤醒,并检查“ExecuteAt”时间超过的第一个任务;然后在一个单独的线程上执行它。
可以通过创建所有超越任务的列表(而不是仅仅第一个)来完成额外的工作;但为了清楚起见,我把它留了出来。
答案 7 :(得分:0)
存在称为Quartz.NET的nu-get。
您可以完全使用它。