Таймер случайно не срабатывает
У меня есть код, который выглядит так
mTestModeMetadataTimer = new System.Threading.Timer(SomeTimerCallback, null, 1000, Timeout.Infinite);
Stopwatch tmStopwatch = new Stopwatch();
private void SomeTimerCallback(object state)
{
// doing minimal work here
Console.WriteLine("{0}: SomeTimerCallback time: {1}", System.Threading.Thread.CurrentThread.ManagedThreadId, tmStopwatch.ElapsedMilliseconds);
tmStopwatch.Restart();
// Better to be on the safe side and do this slightly more than once per second, than slightly less.
mTestModeMetadataTimer.Change(990, Timeout.Infinite);
}
Все работает отлично, за исключением того, что иногда между событиями таймера возникает огромная задержка, как видно из этого вывода консоли.
31: SomeTimerCallback time: 998
21: SomeTimerCallback time: 997
20: SomeTimerCallback time: 999
3: SomeTimerCallback time: 989
3: SomeTimerCallback time: 1000
3: SomeTimerCallback time: 994
37: SomeTimerCallback time: 999
3: SomeTimerCallback time: 991
29: SomeTimerCallback time: 1002
37: SomeTimerCallback time: 1000
3: SomeTimerCallback time: 17568
3: SomeTimerCallback time: 999
29: SomeTimerCallback time: 993
Это небольшая часть довольно значительного приложения. Такое же поведение существовало с System.Timers.Timer и, на самом деле, встречается в различные другие моменты времени в приложении. Я добавил идентификатор потока к выводу консоли этого конкретного таймера, чтобы, надеюсь, получить немного больше информации о том, почему между правильными событиями в одну секунду есть случайное время в 17,5 секунд.
Есть что-то, что я явно делаю не так? Возможно, есть еще какие-то данные, которые я могу собрать, чтобы выяснить, почему мои таймеры ведут себя забавно?
Любые предложения здесь будут с благодарностью.
3 ответа
Из вашего комментария причина, по которой это происходит, заключается в том, что вы исчерпали потоки в пуле потоков. Поскольку каждый поток использовался, таймеру пришлось ждать 17,5 секунд, чтобы поток стал доступен, прежде чем он сможет работать.
Ваши варианты, как я вижу, либо увеличивают максимальное количество потоков в пуле потоков, либо используют другой таймер, который не использует пул потоков (System.Timers.Timer
с объектом синхронизации, который не использует пул потоков(по-прежнему использует пул потоков для его запуска) или System.Windows.Forms.Timer
с сообщением работает насос)
System.Threading.Timer
вызывает обработчик событий в рабочем потоке, полученном из пула потоков CLR. Если пул потоков находится в состоянии голодания, может случиться так, что обратный вызов будет поставлен в очередь, пока поток не будет освобожден.
Чтобы проверить, исчерпываете ли вы пул потоков, вы можете периодически регистрировать количество доступных потоков во время отладки:
int workerThreads;
int completitionPortThreads;
System.Threading.ThreadPool.GetAvailableThreads(out workerThreads, out completitionPortThreads);
Попробуйте с периодическим в конструкторе Timer:
mTestModeMetadataTimer = new System.Threading.Timer(SomeTimerCallback, null, 1000, TimeSpan.FromMilliseconds(990));
Вы уверены, что не были в режиме отладки, и вы позволили времени уйти, прежде чем продолжить?