И System.Timers.Timer
, и System.Threading.Timer
срабатывают с интервалами, которые значительно отличаются от запрошенных. Например:
new System.Timers.Timer(1000d / 20);
дает таймер, который срабатывает 16 раз в секунду, а не 20.
Чтобы убедиться в отсутствии побочных эффектов от слишком длинных обработчиков событий, я написал эту небольшую тестовую программу:
int[] frequencies = { 5, 10, 15, 20, 30, 50, 75, 100, 200, 500 };
// Test System.Timers.Timer
foreach (int frequency in frequencies)
{
int count = 0;
// Initialize timer
System.Timers.Timer timer = new System.Timers.Timer(1000d / frequency);
timer.Elapsed += delegate { Interlocked.Increment(ref count); };
// Count for 10 seconds
DateTime start = DateTime.Now;
timer.Enabled = true;
while (DateTime.Now < start + TimeSpan.FromSeconds(10))
Thread.Sleep(10);
timer.Enabled = false;
// Calculate actual frequency
Console.WriteLine(
"Requested frequency: {0}\nActual frequency: {1}\n",
frequency, count / 10d);
}
Результат выглядит так:
Требуется: 5 Гц; фактическая: 4,8 Гц
запрошенная: 10 Гц; фактическая: 9,1 Гц
запрошенная: 15 Гц; фактическая: 12,7 Гц
запрошенная: 20 Гц; фактическая: 16 Гц
запрошенная: 30 Гц; фактическая: 21,3 Гц
запрошенная: 50 Гц; фактическая: 31,8 Гц
запрошенная: 75 Гц; фактическая: 63,9 Гц
запрошенная: 100 Гц; фактическая: 63,8 Гц
запрошенная: 200 Гц; фактическая: 63,9 Гц
запрошенная: 500 Гц; фактическое: 63,9 Гц
Фактическая частота отклоняется от запрошенной до 36%. (И, очевидно, не может превышать 64 Гц.) Учитывая, что Microsoft рекомендует этот таймер из-за его «большей точности» по сравнению с System.Windows.Forms.Timer
, это меня озадачивает.
Кстати, это не случайные отклонения. Каждый раз это одни и те же ценности. И аналогичная тестовая программа для другого класса таймера, System.Threading.Timer
, показывает точно такие же результаты.
В моей реальной программе мне нужно собирать измерения со скоростью 50 выборок в секунду. Для этого еще не нужна система реального времени. И очень неприятно получать 32 отсчета в секунду вместо 50.
Любые идеи?
@Chris: Вы правы, все интервалы кажутся целыми кратными примерно 1/64 секунды. Кстати, добавление Thread.Sleep (...) в обработчик событий не имеет никакого значения. Это имеет смысл, учитывая, что System.Threading.Timer
использует пул потоков, поэтому каждое событие запускается в свободном потоке.