Запланированное выполнение службы Windows

Если у меня есть служба Windows, которая должна выполнять задачу каждые 30 секунд, что лучше использовать; класс Timer() или цикл, который выполняет задачу, а затем спит в течение нескольких секунд?

class MessageReceiver 
{
    public MessageReceiver()
    {
    }

    public void CommencePolling()
    {
        while (true)
        {
            try 
            {
                this.ExecuteTask();     
                System.Threading.Thread.Sleep(30000);
            }
            catch (Exception)
            {
                // log the exception
            }
        }
    }

    public void ExecutedTask()
    {
        // do stuff
    }
}

class MessageReceiver 
{
    public MessageReceiver()
    {
    }

    public void CommencePolling()
    {
        var timer = new Timer()
            {
                AutoReset = true,
                Interval = 30000,
                Enabled = true
            };

        timer.Elapsed += Timer_Tick;    
    }

    public void Timer_Tick(object sender, ElapsedEventArgs args)
    {
        try 
        {
            // do stuff
        }
        catch (Exception)
        {
            // log the exception
        }
    }
}

Служба Windows создаст экземпляр класса MessageReciever и выполнит метод CommencePolling в новом потоке.

5 ответов

Решение

Я думаю, что это действительно зависит от вашего требования.

Случай 1. Предположим, вы хотите запустить this.ExecuteTask() каждые пять минут, начиная с 12:00 (т.е. 12:00, 12:05, ...), и предположим, что время выполнения this.ExecuteTask() варьируется (например, от 30 секунд до 2 минут), возможно использование таймера вместо Thread.Sleep() кажется более простым способом сделать это (по крайней мере, для меня).

Тем не менее, вы можете добиться этого поведения с Thread.Sleep() а также путем вычисления смещения при получении меток времени при пробуждении потока и при завершении this.ExecuteTask(),

Случай 2. Предположим, вы хотите выполнить задачу в течение следующих 5 минут, сразу после завершения this.ExecuteTask(), с помощью Thread.Sleep() кажется проще. Опять же, вы можете добиться этого поведения и с помощью таймера, сбрасывая таймер каждый раз, одновременно вычисляя смещения this.ExecuteTask() завершается.

Примечание 1, для случая 1 вы должны быть очень осторожны в следующем сценарии: что если this.ExecuteTask() иногда занимает больше, чем период (то есть начинается в 12:05 и заканчивается в 12:13 в приведенном выше примере).

  1. Что это значит для вашего приложения и как оно будет обрабатываться?

    а. Полный отказ - прервать службу или прервать текущее (12:05) выполнение в 12:10 и запустить 12:10.
    б. Ничего страшного (пропустите 12:10 и бегите this.ExecuteTask() в 12:15).

    с. Ничего страшного, но нужно запускать выполнение в 12:10 сразу после завершения задачи в 12:05 (что, если это займет более 5 минут??).

    д. Необходимо запустить выполнение 12:10, даже если в данный момент выполняется 12:05.

    е. что-нибудь еще?

  2. Для политики, которую вы выбрали выше, ваш выбор реализации (таймер или Thread.Sleep()) легко поддержать вашу политику?

Примечание2. В.NET можно использовать несколько таймеров. Пожалуйста, ознакомьтесь со следующим документом (хотя он немного устарел, но кажется, что это хорошее начало): Сравнение классов таймеров в библиотеке классов.NET Framework

Не ответил я, но Джон Сондерс (см. Выше)... ответ можно найти здесь. Для службы Windows, что лучше, ожидание или таймер?

Мне в этом помогут ответы на этот вопрос.

Вы делаете что-нибудь еще в течение этого десяти секундного ожидания? Использование Thread.sleep будет блокировать, мешая вам делать другие вещи. С точки зрения производительности, я не думаю, что вы увидите слишком много различий, но я бы сам не использовал Thread.sleep.

Есть три таймера на выбор - System.Windows.Forms.Timer реализован в главном потоке, тогда как System.Timers.Timer и System.Threading.Timer создают отдельные потоки.

Я считаю, что оба метода эквивалентны. Поток будет в любом случае: либо потому, что вы его создаете, либо потому, что библиотека, реализующая класс Timer, создает его.

Использование класса Timer может быть немного менее затратным с точки зрения ресурсов, поскольку поток, реализующий таймеры, вероятно, отслеживает и другие тайм-ауты.

Другие вопросы по тегам