Является ли класс System.Diagnostics.Stopwatch медленным при повторном вызове? - PullRequest
0 голосов
/ 17 февраля 2012

У меня есть приложение, которое должно передавать пакеты через фиксированные интервалы 33 мс +/- несколько миллисекунд.

Итак, я придумал класс SpinTimer, показанный ниже:

class SpinTimer
{
    public void SpinWait(double waitTimeInSeconds)
    {
        if (waitTimeInSeconds < 0.0)
        {
            throw new ArgumentOutOfRangeException("waitTimeInSeconds", "Must be >= 0.0");
        }

        Stopwatch timer = new Stopwatch();
        double elapsed = 0.0;
        timer.Start();
        do
        {
            elapsed = (double)timer.ElapsedTicks / (double)Stopwatch.Frequency;
        } while (elapsed < waitTimeInSeconds);
    }
}

Однако после профилирования кода я обнаружил, что вызов System.Diagnostics.Stopwatch.GetTimestamp() занимает большую часть времени выполнения. Как примечание, я не могу позволить себе спящий поток и переключение контекста, так как это вызывает слишком большое "дрожание" в скорости вывода.

Замечания о запуске профиля:

  1. Приоритет нити был установлен на ThreadPriority.Highest
  2. Приоритет процесса был установлен на ProcessPriorityClass.High

Исходная программа, которую я написал (на C ++), достигла того же эффекта, используя функции QueryPerformanceCounter() и QueryPerformanceFrequency(). Должен ли я использовать эти вызовы с PInvoke вместо класса Stopwatch? Или есть другой подходящий способ сделать это?

Спасибо!

Ответы [ 3 ]

2 голосов
/ 17 февраля 2012

Вы пытались использовать System.Windows.Threading.DispatcherTimer?

Я создал несколько программ с этим, и никогда не испытывал никаких задержек

2 голосов
/ 17 февраля 2012

Секундомер находится в пространстве имен диагностики. Его не следует использовать для определения уровня производительности.

вам, вероятно, нужен таймер.

1 голос
/ 21 февраля 2012

После некоторой дополнительной отладки (вдохновленной комментариями Эрика Липперта) я понял, что мой код, приведенный выше, работает именно так, как было запрошено. Проблема заключалась в том, что вызывающий код находился на более высоком уровне абстракции, что обеспечивало чрезвычайно долгое время ожидания.

Спасибо за предложения по использованию System.Windows.Threading.DispatcherTimer и System.Timers.Timer (я проголосовал за оба); однако после тестирования каждого из них их точность ограничена ~ 10 миллисекундами, что просто недостаточно для моих целей. Но я обнаружил, что мой код «узкого» цикла с точностью до ~ 1 микросекунды, что более чем достаточно для моих текущих потребностей.

Дополнительным ресурсом, который другие могут найти полезным, является эта статья CodeProject о повышении точности Stopwatch. Основная идея состоит в том, чтобы существенно снизить вероятность того, что ваша программа выдержит переключение контекста, и, таким образом, путешествие по очередям планирования приводит к потере времени.

...