Мы получаем следующую проблему при использовании System.Threading.Timer
(.NET 2.0) от службы Windows.
Кто-то может сказать мне, какова причина для этого поведения и каково решение для этого?
Спасибо, Swati
Объяснение Тимоти убедительно, но System.Threading.Timer уже работает таким образом. По крайней мере, в реализации Rotor он использует значение, возвращаемое GetTickCount (), для вычисления срока следующего обратного вызова. Маловероятно, что реальная среда CLR делает то же самое, скорее всего, будет использоваться CreateTimerQueueTimer (). Тем не менее, эта функция API также, вероятно, будет зависеть от внутреннего тика, увеличиваемого прерыванием тика часов.
Вопрос в том, насколько хорошо внутренние часы (возвращаемые GetTickCount () и Environment.TickCount) синхронизируются с абсолютным временем на стене (возвращаемым DateTime.Now). К сожалению, это деталь реализации HAL на вашем компьютере, уровень аппаратной абстракции. Изготовитель машины может предоставить собственный HAL, настроенный для работы с BIOS и набором микросхем машины.
Я бы ожидал проблем, если бы у машины было два источника синхронизации: микросхема часов, которая была разработана для отслеживания времени на стене и продолжает отсчитывать время, даже если вы отключили питание машины, и другую частоту, доступную на чипсете, которую можно разделить для обеспечения прерывание часов. Оригинальный IBM AT PC работал именно так. Чипу часов обычно можно доверять, часы будут сильно отклоняться, если они не точны. Чипсет не может, сокращение качества генераторов - простой способ сэкономить ни копейки.
Решите проблему, избегая длительных периодов на таймере и пересчитывая следующий срок выполнения из DateTime.Now в обратном вызове.
Это невозможно контролировать, так как это зависит от скорости системы. Если у вас суперкомпьютер, то разницы может быть недостаточно, но если вы на нормальном ПК после долгого выполнения будет разница в интервале таймера.
Надеюсь, что это поможет.
Отличный вопрос ... и вот причина:
"Расчет времени" - непростая вещь, когда дело касается компьютеров ... вы можете никогда никогда не полагайтесь на «интервал», чтобы быть идеальным. Некоторые компьютеры будут «тикать» таймером только каждые 14-15 миллисекунд, некоторые чаще, некоторые реже.
Итак:
Thread.Sleep(1);
Запуск может занять от 1 до 30 миллисекунд.
Вместо этого, если вам нужен более точный таймер - вы должны зафиксировать DateTime, когда вы начинаете, а затем в своих таймерах вам придется проверить, вычтя DateTime.Now и ваше исходное время, чтобы увидеть, является ли это "время". для запуска "вашего кода.
Вот пример кода того, что вам нужно сделать:
DateTime startDate = DateTime.Now;
Затем запустите таймер с интервалом, равным 1 миллисекунде. Затем в вашем методе:
if (DateTime.Now.Subtract(startDate).TotalSeconds % 3 == 0)
{
// This code will fire every 3 seconds.
}
Этот код выше будет точно срабатывать каждые 3 секунды. Вы можете оставить его включенным на 10 лет, и он все равно будет срабатывать каждые 3 секунды.
Возможно, перепланирование выполняется после операции, которая занимает несколько секунд. Или вы не контролируете это?