使用Threads&amp ;;在.NET中调度作业计时器

时间:2013-12-05 20:09:59

标签: .net multithreading timer task

这是要求。

我有一个作业/任务,它将一个参数作为输入并执行一些功能。

我需要使用不同的输入参数在不同的计划时间执行方法DoWork。可以说, 在下午1点,必须使用input1触发DoWork。 在下午1点30分,DoWork必须通过input2触发。 在下午3点,DoWork必须通过input3触发。 ....

这是最好的方法吗? - 使用System.Timer - 使用System.Threading.Timer - 使用TaskFactory&的TaskScheduler

无论我到目前为止尝试过什么,首先都有Windows服务:

public partial class MainJobExecWS : ServiceBase
{
    private Timer taskTimer;

    public MainJobExecWS()
    {
        InitializeComponent();
    }

    protected override void OnStart(string[] args)
    {
        // Define Timer for MainJob
        TimeSpan dueTime = // define starting time of timer;
        TimeSpan repeatingPeriod = // define repeating interval of timer;
        MainJob jm = new MainJob();
        TimerCallback tcb = jm.executeMainJob;
        taskTimer = new Timer(tcb, null, dueTime, repeatingPeriod);   
        base.OnStart(args);
    }

    protected override void OnStop()
    {
        if (taskTimer != null)
        {
            taskTimer.Dispose();
        }
        base.OnStop();
    }
}

主要工作的定义:

class MainJob
    {
        public void executeMainJob(object state)
        {
            // Main Job Definition
        }

        private void scheduleChildJob()
        {
            String childJobInput = "abc"; // How to pass this input to the child job????
            TimeSpan execTimeSpan = // define the timespan for triggering child job;
            ChildJobDef chdJob = new ChildJobDef();
            TimerCallback tcb = chdJob.executeChildJob; 
            Timer timer = new Timer(tcb, null, execTimeSpan, ?); // How to specify that the child job should be triggered only once??
        }
    }

最后是Child Job Definition的定义:

class ChildJobDef
{
    public void executeChildJob(object state)
    {
        // How to get the input sent to this job???
    }
}

2 个答案:

答案 0 :(得分:1)

我发现Reactive Extensions最好地处理这些场景,因为它们的IScheduler接口允许您安排在特定的绝对时间运行的操作(而不是指定相对延迟)。他们的调度程序非常强大,可以补偿时钟漂移,系统时间的变化等等。

使用它们很简单:

DateTimeOffset startTime = /* determine start time */;
Scheduler.Default.Schedule(startTime, () => RunTask1());

答案 1 :(得分:0)

我很无聊所以我把一个使用System.Timers.Timer的演示程序放在一起,安排任务在特定时间的下一个实例运行:

public class ScheduledTask<T>
{
    private T _parameter;
    private Action<T> _action;
    private Timer _timer;

    public ScheduledTask( T parameter, Action<T> action, int hour, int minute, int second )
    {
        Debug.Assert( null != parameter && null != action, "Arg(s) == null" );

        _parameter = parameter;
        _action = action;

        _timer = new Timer( GetIntervalForTimeOfDay( hour, minute, second ) )
        {
            AutoReset = false
        };

        _timer.Elapsed += ( sender, e ) =>
            {
                if( null != TaskStarted )
                {
                    TaskStarted( this, new DateTimeEventArgs( DateTime.Now ) );
                }

                action( _parameter );

                if( null != TaskCompleted )
                {
                    TaskCompleted( this, new DateTimeEventArgs( DateTime.Now ) );
                }
            };

        _timer.Start();
    }

    public static double GetIntervalForTimeOfDay( int hour, int minute, int second )
    {
        Debug.Assert( hour <= 23 && hour >= 0 && minute <= 59 && minute >= 0 && second <= 59 && second >= 0, "Parameter(s) out of range" );

        var now = DateTime.Now;

        var interval = ( new DateTime( now.Year, now.Month, now.Day, hour, minute, second ) )
            .Subtract( now )
            .TotalMilliseconds;

        if( 0.0 > interval )
        {
            interval += 24.0 * 60.0 * 60.0 * 1000.0; // hours in day * minutes in hour * seconds in minute * milliseconds in minute
        }

        return interval;
    }

    public event EventHandler<DateTimeEventArgs> TaskStarted;
    public event EventHandler<DateTimeEventArgs> TaskCompleted;
}

public class DateTimeEventArgs : EventArgs
{
    public DateTime DateTime { get; private set; }

    public DateTimeEventArgs( DateTime dt )
    {
        DateTime = dt;
    }
}

用法:

class Program
{
    static void Main()
    {
        Console.WriteLine( "App started: {0:yyyy-MM-dd HH:mm:ss}", DateTime.Now );

        var st1 = new ScheduledTask<int>( 1, i =>
            {
                System.Threading.Thread.Sleep( 1000 );
                Console.WriteLine( "{0}: {1:yyyy-MM-dd HH:mm:ss}", i, DateTime.Now );
            }, 15, 30, 0 ); // 3:30:00 PM

        st1.TaskStarted += ( sender, e ) => Console.WriteLine( "1 started: {0:yyyy-MM-dd HH:mm:ss}", DateTime.Now );
        st1.TaskCompleted += ( sender, e ) => Console.WriteLine( "1 completed: {0:yyyy-MM-dd HH:mm:ss}", DateTime.Now );

        var st2 = new ScheduledTask<int>( 2, i =>
            {
                System.Threading.Thread.Sleep( 1000 );
                Console.WriteLine( "{0}: {1:yyyy-MM-dd HH:mm:ss}", i, DateTime.Now );
            }, 15, 51, 7 ); // 3:51:07 PM

        st2.TaskStarted += ( sender, e ) => Console.WriteLine( "2 started: {0:yyyy-MM-dd HH:mm:ss}", DateTime.Now );
        st2.TaskCompleted += ( sender, e ) => Console.WriteLine( "2 completed: {0:yyyy-MM-dd HH:mm:ss}", DateTime.Now );


        Console.WriteLine( "App thread paused: {0:yyyy-MM-dd HH:mm:ss}", DateTime.Now );

        Console.ReadLine();
    }
}