65.9K
CodeProject 正在变化。 阅读更多。
Home

.NET 应用程序的任务调度程序库

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.90/5 (6投票s)

2014年6月11日

MIT

1分钟阅读

viewsIcon

38396

downloadIcon

651

一个简单的任务调度程序实用程序,您可以使用它来安排任务在任何时间或间隔运行

引言

这是一个简单的类,可用于安排任务在每天的特定时间运行或按一定间隔运行。 这可用于任何计划任务,例如清理文件或其他资源,将数据从任何外部数据提供程序同步到您的应用程序,定期优化数据库,在带宽使用较少的时段(可能在夜间)发送批量电子邮件或其他通知,例如短信等。

背景

我正在使用 .NET framework >=4.0 的 Task 类。 因此,请检查您的项目是否与此实用程序兼容。

Using the Code

有两种类型的任务调度可用

public enum ScheduleKind
{
    // Scheduler which triggers at a specific time interval
    IntervalBased = 0,
    // Scheduler which runs at a specific time of everyday.
    TimeBased = 1
}

主要的关注类是 Scheduler 类。 这个类继承自 System.Timers.Timer 类并提供任务调度功能。

// Used to schedule tasks to run on regular intervals or on specific time of everyday.
public class Scheduler : Timer, IDisposable
{
    private Scheduler() { }

    private TimeSpan _Time { get; set; }
    private ScheduleKind _Kind { get; set; }

    // Returns a new instance of timer and starts it
    // param name="Time": Interval time to execute the timer
    // param name="Trigger": Function to call in a new Thread when timer elapses, signal time is given as 
    //  input parameter to the function
    // param name="Kind": Specify scheduler type
    // returns: A System.Timers.Timer Instance
    public static Scheduler StartNew(TimeSpan Time, Action<datetime> Trigger,
        ScheduleKind Kind = ScheduleKind.IntervalBased)
    {
        Scheduler timer = MakeTimer(Time, Kind);
        timer.Elapsed += (s, e) => Task.Factory.StartNew(() => Trigger(e.SignalTime));
        return timer;
    }

    // Returns a new instance of timer and starts it
    // param name="Time": Interval time to execute the timer
    // param name="Trigger": Function to call in a new Thread when timer elapses, signal time is given as 
    //  input parameter to the function
    // param name="Kind": Specify scheduler type
    // param name="CallBackFn": Optional call back Action to execute after completing the Trigger function. 
    //  Input parameter of this Action is the result of Trigger function
    // returns: A System.Timers.Timer Instance
    public static Scheduler StartNew<t>(TimeSpan Time, Func<datetime> Trigger,
        ScheduleKind Kind = ScheduleKind.IntervalBased, Action<t> CallBackFn = null)
    {
        Scheduler timer = MakeTimer(Time, Kind);
        timer.Elapsed += (s, e) =>
        {
            if (CallBackFn != null)
            {
                Task.Factory.StartNew(() => Trigger(e.SignalTime))
                    .ContinueWith(prevTask => CallBackFn(prevTask.Result));
            }
            else
            {
                Task.Factory.StartNew(() => Trigger(e.SignalTime));
            }
        };
        return timer;
    }

    // Returns a new instance of timer and starts it
    // param name="Time">Interval time to execute the timer
    // param name="Trigger": Function to call in a new Thread when timer elapses, signal time is given as 
    //  input parameter to the function
    // param name="Kind": Specify scheduler type
    // param name="CallBackFn": Optional call back function to execute after completing the Trigger function. 
    //  Input parameter of this function is the result of Trigger function
    // returns: A System.Timers.Timer Instance
    public static Scheduler StartNew<t, v>(TimeSpan Time, Func<datetime> Trigger,
        ScheduleKind Kind = ScheduleKind.IntervalBased, Func<t, v> CallBackFn = null)
    {
        Scheduler timer = MakeTimer(Time, Kind);
        timer.Elapsed += (s, e) =>
        {
            if (CallBackFn != null)
            {
                Task.Factory.StartNew(() => Trigger(e.SignalTime))
                    .ContinueWith(prevTask => CallBackFn(prevTask.Result));
            }
            else
            {
                Task.Factory.StartNew(() => Trigger(e.SignalTime));
            }
        };
        return timer;
    }

    // Resets and restarts the scheduler
    public void Reset()
    {
        Stop();
        switch (_Kind)
        {
            case ScheduleKind.IntervalBased:
                Interval = _Time.TotalMilliseconds;
                break;
            case ScheduleKind.TimeBased:
                Interval = GetTimeDiff();
                break;
        }
        Enabled = true;
        Start();
    }

    // Creates a timer
    private static Scheduler MakeTimer(TimeSpan Time, ScheduleKind Kind = ScheduleKind.IntervalBased)
    {
        var timer = new Scheduler { _Time = Time, _Kind = Kind };
        timer.Reset();
        return timer;
    }

    // Returns TimeSpan difference of the next schedule time relative to current time
    private double GetTimeDiff()
    {
        try
        {
            // Scheduled time of today
            var nextRunOn =
                DateTime.Today.AddHours(_Time.Hours).AddMinutes(_Time.Minutes).AddSeconds(_Time.Seconds);
            if (nextRunOn < DateTime.Now)
            {
                nextRunOn = nextRunOn.AddMinutes(1);
            }
            if (nextRunOn < DateTime.Now) // If nextRunOn time is already past, set to next day
            {
                nextRunOn = nextRunOn.AddDays(1);
            }
            return (nextRunOn - DateTime.Now).TotalMilliseconds;
        }
        catch (Exception ex)
        {
            ex.WriteLog();
            return 24 * 60 * 60 * 1000;
        }
    }

    // Stop and dispose the timer
    protected override void Dispose(bool disposing)
    {
        Stop();
        base.Dispose(disposing);
    }
}

使用 Scheduler 类非常简单。

// A function that executes every 5 minutes
FiveMinScheduler = Scheduler.StartNew(TimeSpan.FromMinutes(5), 
_ => FiveMinScheduledFn()); // Runs on every 5 minutes

// A function that executes only once in a day at a specific time
NightScheduler = Scheduler.StartNew(TimeSpan.FromHours(2), NightScheduledFn, ScheduleKind.TimeBased); // Runs on 2AM everyday

// Using parameters in a schedule function
ParamerizedScheduler = Scheduler.StartNew(TimeSpan.FromDays(7), 
_ => ParamerizedScheduledFn(i, 6)); // Runs once in a week

// Using result of scheduled function in another callback function
CallbackScheduler = Scheduler.StartNew(TimeSpan.FromSeconds(30), _ => ParamerizedScheduledFn(i, 6),
    ScheduleKind.IntervalBased, CallBackFunc); // Runs on every 15 seconds

以下是以上示例中使用的一些示例方法,这些方法被传递给 Scheduler.StartNew() 帮助程序方法。

internal void NightScheduledFn(DateTime initTime)
{
    Helper.WriteLog("I run at 2AM everyday. Current time is: " + DateTime.Now);
}

internal string ParamerizedScheduledFn(int i, int j)
{
    Helper.WriteLog(String.Format("Got parameters i={0} 
    and j={1}. Current time is: {2}", i, j, DateTime.Now));
    return (i*j).ToString(CultureInfo.InvariantCulture);
}

internal void CallBackFunc(string result)
{
    Helper.WriteLog(String.Format("Scheduled task finished on: {0}. 
    Result of scheduled task is: {1}", DateTime.Now, result));
}

要停止 Scheduler,请调用 schedulerObject.Stop()

要重新启动 Scheduler,请调用 schedulerObject.Reset()

关注点

您可以在附带的源代码中找到一个带有自安装程序选项的 Windows 服务。

同时,查看 使用模板模式的实现行为更改,这是 John Brett 建议的。

注意:这是我在 CodeProject 上的第一篇文章。 请建议改进提示的方法。
© . All rights reserved.