Лучший таймер для использования в службе Windows



мне нужно создать некоторую службу windows, которая будет выполнять каждый N период времени.
Вопрос в том:
Какой таймер управления я должен использовать:System.Timers.Timer или System.Threading.Timer один? Это на что-то влияет?

Я спрашиваю, потому что я слышал много доказательств неправильной работы System.Timers.Timer в службах windows.
Спасибо.

141   6  

6 ответов:

и System.Timers.Timer и System.Threading.Timer будет работать на услуги.

таймеры, которые вы хотите избежать System.Web.UI.Timer и System.Windows.Forms.Timer, которые соответственно для применений ASP и WinForms. Использование их приведет к тому, что служба загрузит дополнительную сборку, которая на самом деле не нужна для типа приложения, которое вы создаете.

использовать System.Timers.Timer, как в следующем примере (также, убедитесь, что что вы используете переменную уровня класса, чтобы предотвратить сбор мусора, как указано в ответе Тима Робинсона):

using System;
using System.Timers;

public class Timer1
{
    private static System.Timers.Timer aTimer;

    public static void Main()
    {
        // Normally, the timer is declared at the class level,
        // so that it stays in scope as long as it is needed.
        // If the timer is declared in a long-running method,  
        // KeepAlive must be used to prevent the JIT compiler 
        // from allowing aggressive garbage collection to occur 
        // before the method ends. (See end of method.)
        //System.Timers.Timer aTimer;

        // Create a timer with a ten second interval.
        aTimer = new System.Timers.Timer(10000);

        // Hook up the Elapsed event for the timer.
        aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);

        // Set the Interval to 2 seconds (2000 milliseconds).
        aTimer.Interval = 2000;
        aTimer.Enabled = true;

        Console.WriteLine("Press the Enter key to exit the program.");
        Console.ReadLine();

        // If the timer is declared in a long-running method, use
        // KeepAlive to prevent garbage collection from occurring
        // before the method ends.
        //GC.KeepAlive(aTimer);
    }

    // Specify what you want to happen when the Elapsed event is 
    // raised.
    private static void OnTimedEvent(object source, ElapsedEventArgs e)
    {
        Console.WriteLine("The Elapsed event was raised at {0}", e.SignalTime);
    }
}

/* This code example produces output similar to the following:

Press the Enter key to exit the program.
The Elapsed event was raised at 5/20/2007 8:42:27 PM
The Elapsed event was raised at 5/20/2007 8:42:29 PM
The Elapsed event was raised at 5/20/2007 8:42:31 PM
...
 */

если вы выберите System.Threading.Timer, вы можете использовать следующим образом:

using System;
using System.Threading;

class TimerExample
{
    static void Main()
    {
        AutoResetEvent autoEvent     = new AutoResetEvent(false);
        StatusChecker  statusChecker = new StatusChecker(10);

        // Create the delegate that invokes methods for the timer.
        TimerCallback timerDelegate = 
            new TimerCallback(statusChecker.CheckStatus);

        // Create a timer that signals the delegate to invoke 
        // CheckStatus after one second, and every 1/4 second 
        // thereafter.
        Console.WriteLine("{0} Creating timer.\n", 
            DateTime.Now.ToString("h:mm:ss.fff"));
        Timer stateTimer = 
                new Timer(timerDelegate, autoEvent, 1000, 250);

        // When autoEvent signals, change the period to every 
        // 1/2 second.
        autoEvent.WaitOne(5000, false);
        stateTimer.Change(0, 500);
        Console.WriteLine("\nChanging period.\n");

        // When autoEvent signals the second time, dispose of 
        // the timer.
        autoEvent.WaitOne(5000, false);
        stateTimer.Dispose();
        Console.WriteLine("\nDestroying timer.");
    }
}

class StatusChecker
{
    int invokeCount, maxCount;

    public StatusChecker(int count)
    {
        invokeCount  = 0;
        maxCount = count;
    }

    // This method is called by the timer delegate.
    public void CheckStatus(Object stateInfo)
    {
        AutoResetEvent autoEvent = (AutoResetEvent)stateInfo;
        Console.WriteLine("{0} Checking status {1,2}.", 
            DateTime.Now.ToString("h:mm:ss.fff"), 
            (++invokeCount).ToString());

        if(invokeCount == maxCount)
        {
            // Reset the counter and signal Main.
            invokeCount  = 0;
            autoEvent.Set();
        }
    }
}

оба примера взяты со страниц MSDN.

Не используйте сервис для этого. Создайте обычное приложение и создайте запланированную задачу для его запуска.

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

" если вы пишете службу Windows, которая запускает таймер, вы должны повторно оценить ваше решение."

- Джон Галлоуэй, ASP.NET менеджер программ сообщества MVC, автор, по совместительству супергерой

либо один должен работать нормально. По сути, система.Нарезка резьбы.Таймер использует систему.Таймеры.Таймер внутри.

сказав это, легко злоупотреблять системой.Таймеры.Таймер. Если вы не храните объект Timer в переменной где-то, то он может быть собран мусор. Если это произойдет, то таймер не сработает. Вызовите метод Dispose, чтобы остановить таймер, или используйте систему.Нарезка резьбы.Класс таймера, который является немного более приятной оберткой.

какие проблемы вы видели пока что?

Я согласен с предыдущим комментарием, что может быть лучше рассмотреть другой подход. Я предлагаю написать консольное приложение и использовать планировщик windows:

Это:

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

как уже было указано как System.Threading.Timer и System.Timers.Timer будет работать. Большая разница между ними заключается в том, что System.Threading.Timer это обертка вокруг другой.

System.Threading.Timer будет иметь больше обработки исключений в то время как System.Timers.Timer проглотит все исключения.

Это дало мне большие проблемы в прошлом, так что я всегда буду использовать 'систему.Нарезка резьбы.Таймер и по-прежнему обрабатывать свои исключения очень хорошо.

Я знаю, что эта тема немного старая, но она пригодилась для конкретного сценария, который у меня был, и я подумал, что стоит отметить, что есть еще одна причина, почему System.Threading.Timer может быть хорошим подходом. Если вам необходимо периодически выполнять задание, которое может занять много времени, и вы хотите убедиться, что весь период ожидания используется между заданиями, или если вы не хотите, чтобы задание выполнялось снова до завершения предыдущего задания в случае, когда задание занимает больше времени, чем период таймера. Вы можно использовать следующее:

using System;
using System.ServiceProcess;
using System.Threading;

    public partial class TimerExampleService : ServiceBase
    {
        private AutoResetEvent AutoEventInstance { get; set; }
        private StatusChecker StatusCheckerInstance { get; set; }
        private Timer StateTimer { get; set; }
        public int TimerInterval { get; set; }

        public CaseIndexingService()
        {
            InitializeComponent();
            TimerInterval = 300000;
        }

        protected override void OnStart(string[] args)
        {
            AutoEventInstance = new AutoResetEvent(false);
            StatusCheckerInstance = new StatusChecker();

            // Create the delegate that invokes methods for the timer.
            TimerCallback timerDelegate =
                new TimerCallback(StatusCheckerInstance.CheckStatus);

            // Create a timer that signals the delegate to invoke 
            // 1.CheckStatus immediately, 
            // 2.Wait until the job is finished,
            // 3.then wait 5 minutes before executing again. 
            // 4.Repeat from point 2.
            Console.WriteLine("{0} Creating timer.\n",
                DateTime.Now.ToString("h:mm:ss.fff"));
            //Start Immediately but don't run again.
            StateTimer = new Timer(timerDelegate, AutoEventInstance, 0, Timeout.Infinite);
            while (StateTimer != null)
            {
                //Wait until the job is done
                AutoEventInstance.WaitOne();
                //Wait for 5 minutes before starting the job again.
                StateTimer.Change(TimerInterval, Timeout.Infinite);
            }
            //If the Job somehow takes longer than 5 minutes to complete then it wont matter because we will always wait another 5 minutes before running again.
        }

        protected override void OnStop()
        {
            StateTimer.Dispose();
        }
    }

    class StatusChecker
        {

            public StatusChecker()
            {
            }

            // This method is called by the timer delegate.
            public void CheckStatus(Object stateInfo)
            {
                AutoResetEvent autoEvent = (AutoResetEvent)stateInfo;
                Console.WriteLine("{0} Start Checking status.",
                    DateTime.Now.ToString("h:mm:ss.fff"));
                //This job takes time to run. For example purposes, I put a delay in here.
                int milliseconds = 5000;
                Thread.Sleep(milliseconds);
                //Job is now done running and the timer can now be reset to wait for the next interval
                Console.WriteLine("{0} Done Checking status.",
                    DateTime.Now.ToString("h:mm:ss.fff"));
                autoEvent.Set();
            }
        }
    Ничего не найдено.

Добавить ответ:
Отменить.