Использование Time.now
(которое возвращает время настенных часов) в качестве базовых линий имеет несколько проблем, которые могут привести к неожиданному поведению. Это вызвано тем фактом, что время настенных часов подвержено изменениям, таким как добавленные високосные секунды или время поворота для настройки местного времени на эталонное время.
Если есть, например, дополнительная секунда, вставленная во время измерения, она будет отключена на секунду. Точно так же, в зависимости от условий локальной системы, вам, возможно, придется иметь дело с переходом на летнее время, с более быстрыми или медленными часами, или с часами, даже скачками во времени, что приводит к отрицательной продолжительности, и многими другими проблемами.
Решением этой проблемы является использование другого времени: монотонных часов. Этот тип часов обладает другими свойствами, чем настенные часы.
Монитонически увеличивается, то есть никогда не возвращается назад и увеличивается с постоянной скоростью. При этом он не представляет настенные часы (то есть время, которое вы читаете из часов на вашей стене), но отметку времени, которую вы можете сравнить с более поздней отметкой времени, чтобы получить разницу.
В Ruby вы можете использовать такую временную метку с Process.clock_gettime(Process::CLOCK_MONOTONIC)
, например:
t1 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
# => 63988.576809828
sleep 1.5 # do some work
t2 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
# => 63990.08359163
delta = t2 - t1
# => 1.5067818019961123
delta_in_milliseconds = delta * 1000
# => 1506.7818019961123
Метод Process.clock_gettime
возвращает метку времени с плавающей запятой с долями секунды. Фактическое возвращаемое число не имеет определенного значения (на которое вы должны полагаться). Однако вы можете быть уверены, что следующий вызов вернет большее число, и, сравнив значения, вы получите разницу в реальном времени.
Эти атрибуты делают метод главным кандидатом для измерения разницы во времени, не видя сбоя вашей программы в самое неподходящее время (например, в полночь в канун Нового года, когда вставляется еще одна секунда).
Используемая здесь константа Process::CLOCK_MONOTONIC
доступна во всех современных системах Linux, BSD и macOS, а также в подсистеме Linux для Windows. Он (насколько мне известно) пока недоступен для «сырых» систем Windows. Там вы можете использовать системный вызов GetTickCount
вместо Process.clock_gettime
, который также возвращает значение таймера с точностью до миллисекунды в Windows.