Поведение таймера, когда выполнение занимает больше времени?
Я пишу службу Windows, которая будет обрабатывать "что-то" каждые пару минут.
Вот какой код:
public Service()
{
this.InitializeComponent();
this.ServiceName = Name;
this.CanPauseAndContinue = true;
this.CanShutdown = true;
this.eventLog.Source = Name;
// initialize timer
this.timer.Elapsed += this.TimerElapsed;
}
private void TimerElapsed(object sender, ElapsedEventArgs e)
{
eventLog.WriteEntry("Starting syncronization...", EventLogEntryType.Information);
if (this.processor.PrepareToRun())
{
this.processor.Run();
}
}
Интересно, что произойдет, если this.processor.Run()
займет много времени, а следующее событие TimerElapsed
будет поднято? Пропустит ли он? Будет ли он ждать и работать как можно скорее? Должен ли я рассматривать эти сценарии и код для них?
Я использую System.Timers.Timer
ИЗМЕНИТЬ
private void TimerElapsed(object sender, ElapsedEventArgs e)
{
eventLog.WriteEntry("Starting syncronization...", EventLogEntryType.Information);
try
{
this.timer.Stop();
if (this.processor.PrepareToRun())
{
this.processor.Run();
}
}
catch (Exception ex)
{
LoggingAndNotifications.LogAndNotify(ex);
}
finally
{
this.timer.Start();
}
}
РЕДАКТИРОВАТЬ 2
public Service()
{
this.InitializeComponent();
this.ServiceName = Name;
this.CanPauseAndContinue = true;
this.CanShutdown = true;
this.eventLog.Source = Name;
// initialize timer
this.timer.AutoReset = false;
this.timer.Elapsed += this.TimerElapsed;
}
private void TimerElapsed(object sender, ElapsedEventArgs e)
{
eventLog.WriteEntry("Starting syncronization...", EventLogEntryType.Information);
try
{
if (this.processor.PrepareToRun())
{
this.processor.Run();
}
}
catch (Exception ex)
{
LoggingAndNotifications.LogAndNotify(ex);
throw;
}
finally
{
this.timer.Start();
}
}
Ответы
Ответ 1
Он снова вызовет его в другом потоке.
В зависимости от характера операции вы также захотите:
- Игнорируйте это, если код называется безопасным для нескольких одновременных вызовов, тогда это может быть хорошо. Конечно, вы должны знать, что все в порядке.
- Блокировка работы таймера. Имейте в виду, что у вас может быть очередь с множеством ожидающих операций, что очень плохо.
- Заблокируйте операцию таймера, попробуйте получить блокировку с тайм-аутом нулевого уровня, а если вы не пройдете, пропустите ее - там есть нить с последнего момента.
- Установите таймер как одноразовый таймер, который вы перезапустите в конце каждого вызова.
Ответ 2
Вы можете увидеть, что произойдет с этим примером приложения:
class Program
{
static void Main(string[] args)
{
System.Timers.Timer timer = new System.Timers.Timer(2000);
timer.Elapsed += new System.Timers.ElapsedEventHandler(OnTimedObject);
timer.Start();
while (true)
{
}
}
static void OnTimedObject(object source, ElapsedEventArgs e)
{
Console.WriteLine("entered");
Thread.Sleep(3000);
Console.WriteLine("exited");
}
}
Вы увидите две строки "введенные", которые появляются до появления "выведенного". Это будет продолжаться. Таким образом, потоки не будут наступать друг на друга.
(Кстати, я не сторонник бесконечных циклов:):)
Ответ 3
Я использую следующее, если я не хочу, чтобы последующие таймеры запускали метод еще до его завершения:
private void TimerFired(object sender, System.Timers.ElapsedEventArgs e) {
// only execute the code within this method if we are able to
// get a lock. This will ensure that any Timer firings will be
// ignored that occur while we're already doing work (OnTimer)
if (Monitor.TryEnter(lockObj)) {
try {
// do work here
} finally {
Monitor.Exit(lockObj);
}
}
}
в противном случае, если метод может иметь продолжительность дольше, чем интервал таймера, метод может начать выполнение в другом потоке до завершения первого.
Ответ 4
Когда событие таймера поднято, код таймера запланирован для исполнения в пуле потоков. Скорее всего, он будет выполнен в другом потоке, но зависит от разных факторов (количество процессоров, использование потоков и т.д.). Однако он не имеет ничего с таймерами - это поток пула.
Лично я никогда не использую таймер. Я устанавливаю таймер для запуска один раз и после выполнения моего кода. Таким образом, я гарантирую, что код выполняется только в одном потоке.
Ответ 5
Я сделал это для обработки таких сценариев. Вне курса вам нужно настроить его для исключительных случаев, таких как многопоточные действия.
public Service()
{
bool _IsProcessRunning = false;
this.InitializeComponent();
this.ServiceName = Name;
this.CanPauseAndContinue = true;
this.CanShutdown = true;
this.eventLog.Source = Name;
// initialize timer
this.timer.Elapsed += this.TimerElapsed;
}
private void TimerElapsed(object sender, ElapsedEventArgs e)
{
if(!_IsProcessRunning)
{
DoSomething();
}
}
private void DoSomething()
{
try
{
_IsProcessRunning = true;
// Do our stuff here
}
catch(Exception Ex)
{
}
finally
{
_IsProcessRunning = false;
}
}
Ответ 6
Поведение таймера, когда выполнение занимает больше времени, чем интервал?
Когда время выполнения задачи займет больше времени, чем таймер. Событие TimerElapsed будет добавлено в новую тему. Он не будет пропущен. Многопоточность, внедренная в System.Timers.Timer