Разница во времени в .NET - PullRequest
1 голос
/ 09 июня 2011

У меня есть следующий код в WinForm:

  Protected Overrides Sub OnMouseMove(ByVal e As System.Windows.Forms.MouseEventArgs)
    Dim startTime = DateTime.Now
    MyBase.OnMouseMove(e)

    Dim result As Double = 45654654
    For i = -1000 To 1000
      result = result / i
    Next i

    Dim endTime = DateTime.Now
    Console.WriteLine(">>> OnMouseMove time = {0}(ms) (start={1}:{3}; end={2}:{4})", (endTime - startTime).TotalMilliseconds, startTime.ToLongTimeString(), endTime.ToLongTimeString(), startTime.Ticks, endTime.Ticks)
  End Sub

Это невероятно, но, похоже, это займет любую миллисекунду, что операции ... ЛЮБОЙ КЛЕЙ !!!

результат

>>> OnMouseMove time = 0(ms) (start=15:56:03:634432317630699089; end=15:56:03:634432317630699089)
>>> OnMouseMove time = 0(ms) (start=15:56:03:634432317630855340; end=15:56:03:634432317630855340)
>>> OnMouseMove time = 0(ms) (start=15:56:03:634432317630855340; end=15:56:03:634432317630855340)
>>> OnMouseMove time = 0(ms) (start=15:56:03:634432317631011591; end=15:56:03:634432317631011591)
>>> OnMouseMove time = 0(ms) (start=15:56:03:634432317631011591; end=15:56:03:634432317631011591)
>>> OnMouseMove time = 0(ms) (start=15:56:03:634432317631167842; end=15:56:03:634432317631167842)

Что-то не так?

В другом городе я пытаюсь уснуть 100 мс

Next i

' sleep 100 ms '
System.Threading.Thread.Sleep(100)

Dim endTime = DateTime.Now

, но вот что удивительно, вместо 100 я гель всегда 93,7506 или 109,3757:

>>> OnMouseMove time = 93,7506(ms) (start=16:05:26:634432323267766416; end=16:05:26:634432323268703922)
>>> OnMouseMove time = 93,7506(ms) (start=16:05:26:634432323268860173; end=16:05:26:634432323269797679)
>>> OnMouseMove time = 109,3757(ms) (start=16:05:26:634432323269797679; end=16:05:27:634432323270891436)
>>> OnMouseMove time = 93,7506(ms) (start=16:05:27:634432323270891436; end=16:05:27:634432323271828942)
>>> OnMouseMove time = 93,7506(ms) (start=16:05:27:634432323271828942; end=16:05:27:634432323272766448)
>>> OnMouseMove time = 109,3757(ms) (start=16:05:31:634432323315891724; end=16:05:31:634432323316985481)

Ответы [ 6 ]

4 голосов
/ 09 июня 2011

Поскольку вы не используете i вне цикла, он, вероятно, оптимизирован. Таким образом, вы синхронизируете два вызова на DateTime.Now и вычитание.

Кроме того, благодаря недавним процессорам, способным отправлять миллиарды операций в секунду, всего несколько тысяч операций (из кэша L1 и регистров при небольшом количестве данных) займет время, измеренное в * микро * секундах.

КСТАТИ. Если вы хотите использовать тайминги, лучше подойдет тип Stopwatch.

2 голосов
/ 09 июня 2011

Вы должны использовать секундомер

как другие опубликовали

далее ..

ваш цикл:

Dim result As Double = 45654654
For i = -1000 To 1000
  result = result / i
Next i

будет удалено

от JIT COMPILER, если у вас есть

Оптимизация так не нужна

2 голосов
/ 09 июня 2011

При попытке измерить истекшее время процессов, особенно коротких процессов, вы хотите использовать лучший инструмент, System.Diagnostics.Stopwatch.

DateTime.Now не будет иметь соответствующей комбинации точности и точности для измерения продолжительности процесса.

Для получения дополнительной информации я советую вам проверить запись в блоге Эрика Липперта .

2 голосов
/ 09 июня 2011

DateTime.Now не имеет высокой точности.Обычно оно составляет около 16 мс по умолчанию и уменьшается до 1 мс, используя timeBeginPeriod.Обратите внимание, что timeBeginPeriod имеет общесистемные эффекты и может увеличить энергопотребление компьютера.Поэтому его не следует использовать легкомысленно.

Представьте, что в ядре есть таймер, который запускает определенную функцию каждые 16 мс.Эта функция обновляет текущее время, используемое DateTime.Now.Затем он решает, какой поток запустить в течение следующих 16 мс.Если вы позвоните sleep(100), ваш поток не будет работать в течение следующих 100 мс.Но Windows не сразу замечает, что 100 мс истекли.Он только замечает следующее событие таймера.И затем он решает снова запустить ваш поток.

Это связано с гранулярностью таймера в окнах и влияет на многие функции API окон, такие как GetTickCount, Sleep, планирование потоков и интервалы таймеров.

Для измерения производительности используйте класс StopWatch, основанный на QueryPerformanceCounter и не страдающий от этой проблемы.(К сожалению, на некоторых многоядерных машинах происходит сбой, когда часы разных ядер рассинхронизируются. Не удивляйтесь, если он скачет назад или вперед во времени для больших интервалов, когда ваш поток запланирован на другом ядре)

1 голос
/ 09 июня 2011

Да.Использование DateTime.Now для измерения точного времени не является точным.Вместо этого используйте Секундомер .

1 голос
/ 09 июня 2011

Попробуйте использовать секундомер, но я мог видеть, что для увеличения целого в 2000 раз требуется менее миллисекунды, учитывая, что современные компьютеры думают с точки зрения наносекунд.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...