Я думаю, что другие ответы не в состоянии адресовать , почему происходит 14мс в каждой итерации кода OP; это , а не из-за неточных системных часов (и DateTime.Now
не является неточным, если вы не отключили службы NTP или не настроили неправильный часовой пояс или что-то глупое! Это всего лишь неточно ).
Точный таймер
Даже с неточными системными часами (использующими DateTime.Now
, или с подключением солнечного элемента к АЦП, чтобы узнать, как высоко солнце в небе, или делением времени между пиковыми потоками, или ... ) код, следующий за этим шаблоном, будет иметь среднее отклонение по нулю (он будет совершенно точным с точностью в среднем ровно одну секунду между тиками):
var interval = new TimeSpan(0, 0, 1);
var nextTick = DateTime.Now + interval;
while (true)
{
while ( DateTime.Now < nextTick )
{
Thread.Sleep( nextTick - DateTime.Now );
}
nextTick += interval; // Notice we're adding onto when the last tick was supposed to be, not when it is now
// Insert tick() code here
}
(Если вы копируете и вставляете это, следите за случаями, когда ваш тиковый код выполняется дольше, чем interval
. Я оставлю это в качестве упражнения для читателя, чтобы найти простые способы сделать это пропускает столько ударов, сколько нужно, чтобы nextTick
приземлился в будущем)
Неточный таймер
Я предполагаю, что реализация Microsoft System.Threading.Timer следует за этим шаблоном. Этот шаблон всегда будет изменяться даже с совершенно точным и совершенно точным системным таймером (потому что требуется время, чтобы выполнить даже только операцию добавления):
var interval = new TimeSpan(0, 0, 1);
var nextTick = DateTime.Now + interval;
while (true)
{
while ( DateTime.Now < nextTick )
{
Thread.Sleep( nextTick - DateTime.Now );
}
nextTick = DateTime.Now + interval; // Notice we're adding onto .Now instead of when the last tick was supposed to be. This is where slew comes from
// Insert tick() code here
}
Так что для людей, которые могут быть заинтересованы в использовании собственного таймера, не следуйте этой второй схеме.
Точное измерение времени
Как говорили другие авторы, класс Stopwatch
дает большую точность для измерения времени, но совсем не помогает с точностью , если следовать неправильному шаблону. Но, , как сказал @Shahar , вы никогда не получите идеально точный таймер, поэтому вам нужно переосмыслить вещи, если совершенная точность - это то, что вы ' после.
Отказ от ответственности
Обратите внимание, что Microsoft мало говорит о внутренностях класса System.Threading.Timer , так что я очень умело размышляю об этом, но если это крякает как утка, то это, вероятно, утка. Кроме того, я понимаю, что этому уже несколько лет, но это все еще актуальный (и я думаю, без ответа) вопрос.
Редактировать: изменена ссылка на ответ @ Shahar
Редактировать: Microsoft имеет исходный код для многих онлайн-материалов, в том числе System.Threading.Timer , для всех, кому интересно посмотреть, как Microsoft реализовала этот таймер отключения