2013-12-05 5 views
0

Это требование.Планирование работы в .NET с использованием потоков и таймеров

У меня есть работа/задача, которая принимает один параметр в качестве входных данных и выполняет некоторую функцию.

Мне нужно выполнить метод DoWork при разных таймингах расписания с разными входными параметрами. Допустим, в 13:00, DoWork должен быть запущен с помощью input1. в 13:30, DoWork должен запускаться с input2. в 3 часа дня, DoWork должен запускаться с вводом3. ....

Какой лучший способ сделать это? - Использование 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(); 
    } 
} 

Определение для Main Работа:

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?? 
     } 
    } 

И, наконец, определение определение Ребенка работы:

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

Можете ли вы показать нам, что вы делали до сих пор? Каков ваш первоначальный дизайн? – user2942249

+0

Мой первоначальный дизайн был полностью основан на Quartz.NET, но по некоторым внутренним причинам мне пришлось покинуть Quartz. – wesfaith

+0

Я отредактировал свой вопрос, чтобы отобразить основной подход. – wesfaith

ответ

1

Я считаю, что реактивные расширения лучше всего справляются с этими сценариями, так как их интерфейс IScheduler позволяет планировать действия для запуска в определенное абсолютное время (в отличие от указания относительной задержки). Их планировщики являются довольно устойчивыми, и компенсирует часов дрейфа, изменения системного времени и т.д.

С их помощью легко:

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

но что, если 'Now' сегодня в 2:00? – Moho

+0

Хорошая точка. Я отредактировал ответ, чтобы избежать вычисления даты «глупым примером» из буквально. –

+1

У меня есть целая рамка планирования при работе, построенная на вершине Rx и NCrontab. Очень рекомендую этот маршрут. –

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(); 
    } 
} 
+0

Hi Moho .. Я новичок в .NET, поэтому для понимания вашего подхода потребуется некоторое время. – wesfaith

+0

, но один из основных моментов в моем требовании - это основное задание, которое планируется запустить каждые 5 минут с использованием таймера. это основное задание (во время его индивидуального выполнения) запланирует выполнение дочерних заданий (указано в моем исходном вопросе) .. так что это основное задание не дожидаться, пока запланированы и будут выполнены детские задания .. как это сделать ??? – wesfaith

Смежные вопросы