Таймер случайно не срабатывает

У меня есть код, который выглядит так

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));

Вы уверены, что не были в режиме отладки, и вы позволили времени уйти, прежде чем продолжить?

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