Подтвердить что ты не робот

Может ли класс .NET Stopwatch быть этим страшным?

Я делаю приложение, которое требует довольно жесткого времени, а класс Stopwatch - идеальное решение. Тем не менее, иногда я заметил, что при работе на ПК с маленькими панелями значения секундомера уходили. Я добавил некоторые отладочные распечатки, которые отслеживают значение секундомера каждые 200 мкс или около того:

0: 00: 197
0: 00: 502
0: 00: 702
...
0: 03: 356
0:12:93

0:13:21
0: 13: 421
...

Как он может прыгать с ~ 3 секунд до ~ 13 секунд? Теперь я вижу, что основная функция QueryPerformanceCounter() ошибочна (Опасайтесь QueryPerformanceCounter()), но я понимаю, что что-то еще происходит здесь.

Любое понимание понимается.

Update:

Вот немного более подробно о моем коде: это довольно просто. Это приложение WPF, которое создает новый объект Stopwatch при запуске, а затем отключает его через Start(). Затем я создаю DispatcherTimer, например:

displayTimer = new DispatcherTimer(); 
displayTimer.Tick += display_Tick; 
displayTimer.Interval = DISPLAY_INTERVAL_TIMESPAN; 

где время составляет 200 мкс. Мой код отладки просто выводит значение объекта Stopwatch каждый раз, когда тики dispatchTimer.

Отладочный журнал находится в dl.dropbox.com/u/7999907/hburg.txt. Первый бит данных в каждой строке - текущая дата/время через DateTime.UtcNow. Время вправо - это значение через Stopwatch.Elapsed. Вы можете увидеть, как прыгает секундомер, но DateTime не делает.

Update2:

Веселая статья поддержки Microsoft Значение счетчика производительности может неожиданно перескочить вперед.

4b9b3361

Ответ 1

Обновить (после просмотра вашего журнала)

Как вы уже упоминали, класс Stopwatch использует QueryPerformanceCounter под ним. В разделе Замечания MSDN говорит:

На многопроцессорном компьютере не имеет значения, какой процессор вызывается. Однако вы можете получать разные результаты на разных процессорах из-за ошибок в базовой системе ввода-вывода (BIOS) или слоя абстракции оборудования (HAL). Чтобы указать сродство процессора к потоку, используйте функцию SetThreadAffinityMask.

Поскольку вы используете диспетчер, QueryPerformanceCounter может не выполняться на одном CPU каждый раз, когда вы запрашиваете прошедшее время.

Вы можете проверить, является ли проблема, упомянутая в MSDN, причиной вашей проблемы, указав сродство процессора к вашему процессу, например. вызывая ваш исполняемый файл с помощью команды start. 10 секунд кажется большим отставанием между процессорами для меня, но документация очень расплывчата в отношении того, насколько велика разница. Следующая команда привяжет ваше приложение к первому процессору:

> start.exe /AFFINITY 1 program.exe

Если это должно решить проблему, вы можете захотеть взглянуть на предлагаемое решение, то есть вызвать функцию SetThreadAffinityMask перед запросом объекта Stopwatch.

<ы > Ваш комментарий сказал, что вы используете WPF DispatcherTimer. В документации этого класса указано:

Таймеры не гарантируют выполнение точно, когда происходит интервал времени, но они гарантированно не выполняются до того, как произойдет интервал времени. Это связано с тем, что операции DispatcherTimer помещаются в очередь диспетчера, как и другие операции. При выполнении операции DispatcherTimer зависит от других заданий в очереди и их приоритетов.

Это означает, что событие таймера может задерживаться, особенно если диспетчер занят другими задачами. Вы размещали другие вещи в очереди диспетчера, что предотвратит запуск события раньше? С >

Ответ 2

Точный выбор времени для аппаратного обеспечения ПК не является простым, периодом. Вот некоторые ресурсы, демонстрирующие некоторый опыт синхронизации в Windows, который будет основной реализацией любого счетчика в среде Windows, включая .NET:

Это объясняет, почему иногда вы получаете разрешение 10 ms, в зависимости от того, какой системный вызов вы используете, и проливает немного больше света на то, почему QueryPerformanceCounter "глючит". Один из пунктов состоит в том, что режимы энергосбережения/переменные скорости процессора могут помешать этим таймингам.

Связанная с этим концепция - "блокировка времени" в физическом моделировании в реальном времени. Если вы Google для этого, вы можете получить некоторые идеи о том, как работать с проблемами, которые у вас есть. Основная концепция заключается в том, что у вас есть фиксированные временные шаги, и вы делаете своего рода реализацию производителя/потребителя для ваших функций синхронизации/обновления. Я не знаю, относится ли это к вашему конкретному домену, но считается лучшим в видеоиграх.

Ответ 3

Возможно, я не понимаю ваш вопрос, но нужно ли просто измерять интервалы времени или вам нужно выполнять код на этих интервалах? Если вам нужно выполнить код, то проверьте класс System.Timers.Timer, поскольку он потокобезопасен и должен отлично работать для нескольких процессоров.