Правильно измерьте продолжительность времени в Go
Каков правильный способ точно измерить продолжительность времени в Go?
В большинстве приложений используется стандартный пакет времени и следующий подход:
var startTime = time.Now()
doSomeHardWork()
var duration = time.Since(startTime) // or: time.Now() - startTime
Однако time.Now()
возвращает текущее системное время, что приводит к двум недостаткам:
- Если системное время изменяется во время измерения (например, из-за изменения часового пояса (DST) или прыжок второй), результирующая продолжительность также неверна.
-
Системное время может зацикливаться быстрее или медленнее, чем в реальном времени. Это всегда происходит, когда операционная система синхронизирует внутренние часы с серверами времени NTP (что может происходить несколько раз в час!)
От MSDN:
[Служба времени] настраивает локальную тактовую частоту, чтобы сходятся к правильному времени. Если разница во времени между локальные часы и [точный отсчет времени] слишком велики, чтобы настраивая местную тактовую частоту, служба времени устанавливает локальные часы на правильное время.
Если системное время изменяется (вручную или из-за DST), возможно, будет обнаружена недействительная продолжительность и отброшена. Но если системные часы гаснут, например. На 10% быстрее синхронизироваться с мировым временем, его практически невозможно обнаружить. Это предполагаемое поведение и способы создания системных часов.
По этой причине большинство других языков предлагают специальный API для измерения продолжительности:
Каков правильный способ точно измерить время выполнения в Go?
Ответы
Ответ 1
Время пакета
Монотонные часы
Операционные системы предоставляют как "настенные часы", которые подлежат изменения для синхронизации часов и "монотонные часы", которые не. Общее правило заключается в том, что настенные часы предназначены для монотонные часы предназначены для измерения времени. Вместо того, чтобы разделить API, в этом пакете Время, возвращенное временем. Теперь содержит и стену чтение часов и чтение монотонных часов; позднее расписание операции используют считывание настенных часов, но позднее измерение времени операции, в частности сравнения и вычитания, используйте чтение монотонных часов.
Например, этот код всегда вычисляет положительное истекшее время приблизительно 20 миллисекунд, даже если настенные часы изменены во время выполнения операции:
start := time.Now()
... operation that takes 20 milliseconds ...
t := time.Now()
elapsed := t.Sub(start)
Другие идиомы, такие как time.Since(начало), time.Until(крайний срок) и time.Now(). До (крайний срок) аналогично надежны против настенных часов переустанавливает.
Начиная с Go 1.9 (выпущенный 24 августа 2017 года), Go использует монотонные часы для продолжительности.
См. Предложение: Монотонные измерения прошедшего времени в Go.
Ответ 2
Это доступно в Go 1.9 (август 2017 года) с монотонными часами, вам не нужно ничего делать, чтобы извлечь из этого выгоду:
https://tip.golang.org/pkg/time/#hdr-Monotonic_Clocks
Операционные системы предоставляют как "настенные часы", которые подлежат изменения для синхронизации часов и "монотонные часы", которые не. Общее правило заключается в том, что настенные часы предназначены для монотонные часы предназначены для измерения времени. Вместо того, чтобы разделить API, в этом пакете Время, возвращенное временем. Теперь содержит и стену чтение часов и чтение монотонных часов; позднее расписание операции используют считывание настенных часов, но позднее измерение времени операции, в частности сравнения и вычитания, используйте чтение монотонных часов.
Например, этот код всегда вычисляет положительное истекшее время приблизительно 20 миллисекунд, даже если настенные часы изменены во время выполнения операции:
start := time.Now()
... operation that takes 20 milliseconds ...
t := time.Now()
elapsed := t.Sub(start)
Другие идиомы, такие как time.Since(начало), time.Until(крайний срок) и time.Now(). До (крайний срок) аналогично надежны против настенных часов переустанавливает.
Это изменение time pkg было вызвано этим issue, что вызвало это proposal для изменения от Russ Cox:
Сравнение и вычитание времени, наблюдаемого по времени. Теперь можно вернуться неверные результаты, если системные настенные часы reset между двумя наблюдения. Мы предлагаем продлить время. Временное представление провести дополнительное чтение монотонных часов для использования в этих расчеты. Среди других преимуществ это должно сделать невозможным базовое измерение прошедшего времени с использованием времени. Теперь и время. Поскольку сообщать о отрицательной продолжительности или о другом результате, не обоснованном в действительности.
Ответ 3
Для Go 1.8 и ранее правильная функция синхронизации не находится внутри временного пакета, а вместо этого в пакет времени выполнения:
func nanotime() int64
Чтобы правильно измерить время выполнения, следует использовать следующую процедуру:
var startTime = runtime.nanotime()
doSomeHardWork()
var duration = runtime.nanotime() - startTime
К сожалению, сам метод документально не документирован. Он появился в этой проблеме после долгого обсуждения