MyTetra Share
Делитесь знаниями!
Модуль time – таймеры времени
09.08.2018
00:05
Раздел: Python - Модули


Модуль time – таймеры времени

Модуль Python time обеспечивает доступ к нескольким различным типам, каждые из которых применяются для разных целей. Функция monotonic() может использоваться для измерения прошедшего времени в длительном процессе. Она никогда не уменьшает значение времени, даже если изменяется системное время.

Для тестирования производительности perf_counter() обеспечивает доступ к таймерам с самым высоким дроблением единиц времени для более точного измерения. Время CPU доступно через clock(), а process_time() возвращает комбинированное значение времени процессора и системы.

Примечание

В реализациях представлены функции библиотеки C для управления датами и временем. Поскольку они связаны с базовой реализацией языка C, некоторые элементы (такие как начало эпохи и максимальное значение даты) зависят от платформы. Подробную информацию смотрите в документации к библиотеке.

Сравнение часов

Детали реализации таймера в Python модуле time зависят от платформы. Используйте get_clock_info() для получения основной информации о текущей реализации, включая доступную точность часов:

  1. time_get_clock_info.py
  2. import textwrap
  3. import time
  4. available_clocks = [
  5. ('clock', time.clock),
  6. ('monotonic', time.monotonic),
  7. ('perf_counter', time.perf_counter),
  8. ('process_time', time.process_time),
  9. ('time', time.time),
  10. ]
  11. for clock_name, func in available_clocks:
  12. print(textwrap.dedent('''
  13. {name}:
  14. adjustable : {info.adjustable}
  15. implementation: {info.implementation}
  16. monotonic : {info.monotonic}
  17. resolution : {info.resolution}
  18. current : {current}
  19. ''').format(
  20. name=clock_name,
  21. info=time.get_clock_info(clock_name),
  22. current=func())
  23. )


Этот вывод для Mac OS X показывает, что Python time таймеры monotonic и perf_counter реализованы с использованием одного и того же базового системного вызова:

  1. $ python3 time_get_clock_info.py
  2. clock:
  3. adjustable : False
  4. implementation: clock()
  5. monotonic : True
  6. resolution : 1e-06
  7. current : 0.028399
  8. monotonic:
  9. adjustable : False
  10. implementation: mach_absolute_time()
  11. monotonic : True
  12. resolution : 1e-09
  13. current : 172336.002232467
  14. perf_counter:
  15. adjustable : False
  16. implementation: mach_absolute_time()
  17. monotonic : True
  18. resolution : 1e-09
  19. current : 172336.002280763
  20. process_time:
  21. adjustable : False
  22. implementation: getrusage(RUSAGE_SELF)
  23. monotonic : True
  24. resolution : 1e-06
  25. current : 0.028593
  26. time:
  27. adjustable : True
  28. implementation: gettimeofday()
  29. monotonic : False
  30. resolution : 1e-06
  31. current : 1471198232.045526


Основной таймер

Одной из функций ядра Python модуля time является функция time(), которая возвращает количество секунд с момента начала «эпохи» в виде значения с плавающей запятой:

  1. time_time.py
  2. import time
  3. print('The time is:', time.time())


Эпоха — это начало измерения времени, которым для систем Unix является 0:00 1 января 1970 года. Хотя значение всегда является числом с плавающей запятой, фактическая точность зависит от платформы:

  1. $ python3 time_time.py
  2. The time is: 1471198232.091589


Десятичная дробь полезна при хранении или сравнении дат, но не для создания читаемых человеком представлений. Для регистрации или вывода времени более полезной может оказаться функция ctime():

  1. $ python3 time_ctime.py
  2. The time is : Sun Aug 14 14:10:32 2016
  3. 15 secs from now : Sun Aug 14 14:10:47 2016


Второй вызов print() в этом примере иллюстрирует, как использовать ctime() для форматирования значения времени, которое отличается от текущего:

  1. $ python3 time_ctime.py
  2. The time is : Sun Aug 14 14:10:32 2016
  3. 15 secs from now : Sun Aug 14 14:10:47 2016


Таймер относительного времени

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

Избегайте таких ситуаций путем использования функции monotonic(), у которой возвращаемое при повторном вызове значение всегда больше предыдущего:

  1. time_monotonic.py
  2. import time
  3. start = time.monotonic()
  4. time.sleep(0.1)
  5. end = time.monotonic()
  6. print('start : {:>9.2f}'.format(start))
  7. print('end : {:>9.2f}'.format(end))
  8. print('span : {:>9.2f}'.format(end - start))


Начальная точка для относительных таймеров не определена, поэтому возвращаемые значения могут использоваться только для расчетов с другими значениями времени. В этом примере продолжительность спящего режима измеряется с помощью monotonic():

  1. $ python3 time_monotonic.py
  2. start : 172336.14
  3. end : 172336.24
  4. span : 0.10


Таймер процессора

В то время как time() возвращает время основных часов, clock() возвращает время процессора. Для этого можно использовать Python get time.

Значения, возвращаемые функцией clock(), отражают фактическое время, используемое программой при ее запуске:

  1. time_clock.py
  2. import hashlib
  3. import time
  4. # Данные, используемые для вычисления контрольной суммы md5
  5. data = open(__file__, 'rb').read()
  6. for i in range(5):
  7. h = hashlib.sha1()
  8. print(time.ctime(), ': {:0.3f} {:0.3f}'.format(
  9. time.time(), time.clock()))
  10. for i in range(300000):
  11. h.update(data)
  12. cksum = h.digest()


В этом примере отформатированная ctime() выводится вместе со значениями с плавающей запятой из time() и clock() через цикл для каждой итерации.

Примечание

Если хотите запустить этот код в своей системе, то может потребоваться добавить во внутренний цикл другие циклы или придется работать с большим количеством данных, чтобы увидеть разницу во времени с помощью Python time:

  1. $ python3 time_clock.py
  2. Sun Aug 14 14:10:32 2016 : 1471198232.327 0.033
  3. Sun Aug 14 14:10:32 2016 : 1471198232.705 0.409
  4. Sun Aug 14 14:10:33 2016 : 1471198233.086 0.787
  5. Sun Aug 14 14:10:33 2016 : 1471198233.466 1.166
  6. Sun Aug 14 14:10:33 2016 : 1471198233.842 1.540


Как правило, часы процессора ничего не засекают, если программа ничего не делает:

  1. time_clock_sleep.py
  2. import time
  3. template = '{} - {:0.2f} - {:0.2f}'
  4. print(template.format(
  5. time.ctime(), time.time(), time.clock())
  6. )
  7. for i in range(3, 0, -1):
  8. print('Sleeping', i)
  9. time.sleep(i)
  10. print(template.format(
  11. time.ctime(), time.time(), time.clock())
  12. )


В этом примере Python 3 time sleep цикл выполняет мало действий, переходя в спящий режим после каждой итерации. Значение time() увеличивается даже тогда, когда приложение находится в спящем режиме, но значение clock() отсутствует:

  1. $ python3 -u time_clock_sleep.py
  2. Sun Aug 14 14:10:34 2016 - 1471198234.28 - 0.03
  3. Sleeping 3
  4. Sun Aug 14 14:10:37 2016 - 1471198237.28 - 0.03
  5. Sleeping 2
  6. Sun Aug 14 14:10:39 2016 - 1471198239.29 - 0.03
  7. Sleeping 1
  8. Sun Aug 14 14:10:40 2016 - 1471198240.29 - 0.03


Вызов sleep() передает управление из текущего потока и указывает ожидать, пока система активирует его. Если программа имеет только один поток, это эффективно блокирует приложение, и оно не работает.

Счетчик производительности

Для измерения производительности важно иметь таймеры monotonic с высокой точностью. Определение наилучшего источника данных синхронизации требует наличия информации о платформе, которую Python предоставляет в perf_counter():

  1. time_perf_counter.py
  2. import hashlib
  3. import time
  4. # Data to use to calculate md5 checksums
  5. data = open(__file__, 'rb').read()
  6. loop_start = time.perf_counter()
  7. for i in range(5):
  8. iter_start = time.perf_counter()
  9. h = hashlib.sha1()
  10. for i in range(300000):
  11. h.update(data)
  12. cksum = h.digest()
  13. now = time.perf_counter()
  14. loop_elapsed = now - loop_start
  15. iter_elapsed = now - iter_start
  16. print(time.ctime(), ': {:0.3f} {:0.3f}'.format(
  17. iter_elapsed, loop_elapsed))


Как и в случае с функцией Python time monotonic(), эпоха для perf_counter() не определяется. Значения предназначены для сравнения и вычисления, а не в качестве абсолютных значений:

  1. $ python3 time_perf_counter.py
  2. Sun Aug 14 14:10:40 2016 : 0.487 0.487
  3. Sun Aug 14 14:10:41 2016 : 0.485 0.973
  4. Sun Aug 14 14:10:41 2016 : 0.494 1.466
  5. Sun Aug 14 14:10:42 2016 : 0.487 1.953
  6. Sun Aug 14 14:10:42 2016 : 0.480 2.434


Компоненты времени

Хранимое в виде прошедших секунд время используется в некоторых ситуациях. Но иногда программа должна иметь доступ к отдельным полям даты (год, месяц и т. д.). Модуль времени определяет struct_time для хранения значений даты и времени с разбитыми компонентами, поэтому они легко доступны. Существует несколько функций, которые работают со значениями struct_time вместо float:

  1. time_struct.py
  2. import time
  3. def show_struct(s):
  4. print(' tm_year :', s.tm_year)
  5. print(' tm_mon :', s.tm_mon)
  6. print(' tm_mday :', s.tm_mday)
  7. print(' tm_hour :', s.tm_hour)
  8. print(' tm_min :', s.tm_min)
  9. print(' tm_sec :', s.tm_sec)
  10. print(' tm_wday :', s.tm_wday)
  11. print(' tm_yday :', s.tm_yday)
  12. print(' tm_isdst:', s.tm_isdst)
  13. print('gmtime:')
  14. show_struct(time.gmtime())
  15. print('nlocaltime:')
  16. show_struct(time.localtime())
  17. print('nmktime:', time.mktime(time.localtime()))


Функция Python модуля time gmtime() возвращает текущее время в UTC. Localtime() возвращает текущее время с использованием текущего часового пояса. Mktime() принимает struct_time и преобразует его в формат с плавающей запятой:

  1. $ python3 time_struct.py
  2. gmtime:
  3. tm_year : 2016
  4. tm_mon : 8
  5. tm_mday : 14
  6. tm_hour : 18
  7. tm_min : 10
  8. tm_sec : 42
  9. tm_wday : 6
  10. tm_yday : 227
  11. tm_isdst: 0
  12. localtime:
  13. tm_year : 2016
  14. tm_mon : 8
  15. tm_mday : 14
  16. tm_hour : 14
  17. tm_min : 10
  18. tm_sec : 42
  19. tm_wday : 6
  20. tm_yday : 227
  21. tm_isdst: 1
  22. mktime: 1471198242.0


Работа с часовыми поясами

Выбор функции для определения текущего времени зависит от того, установлен ли часовой пояс программой или системой. Изменение часового пояса не изменяет фактическое время — только способ его представления.

Чтобы изменить часовой пояс, установите переменную среды TZ, затем вызовите tzset(). Часовой пояс можно указать с различными данными, вплоть до времени начала и завершения периода так называемого «летнего» времени. Проще всего использовать название часового пояса, но базовые библиотеки получают и другую информацию.

Приведенная ниже программа без Python time sleep, и задает несколько разных значений для часового пояса и показывает, как изменения влияют на другие настройки в модуле времени:

  1. time_timezone.py
  2. import time
  3. import os
  4. def show_zone_info():
  5. print(' TZ :', os.environ.get('TZ', '(not set)'))
  6. print(' tzname:', time.tzname)
  7. print(' Zone : {} ({})'.format(
  8. time.timezone, (time.timezone / 3600)))
  9. print(' DST :', time.daylight)
  10. print(' Time :', time.ctime())
  11. print()
  12. print('Default :')
  13. show_zone_info()
  14. ZONES = [
  15. 'GMT',
  16. 'Europe/Amsterdam',
  17. ]
  18. for zone in ZONES:
  19. os.environ['TZ'] = zone
  20. time.tzset()
  21. print(zone, ':')
  22. show_zone_info()


Часовой пояс по умолчанию для системы, используемой в примерах — US / Eastern. Другие зоны в примере Python модуля time изменяют значение tzname, продолжительности светового дня и значение смещения часового пояса:

  1. $ python3 time_timezone.py
  2. Default :
  3. TZ : (not set)
  4. tzname: ('EST', 'EDT')
  5. Zone : 18000 (5.0)
  6. DST : 1
  7. Time : Sun Aug 14 14:10:42 2016
  8. GMT :
  9. TZ : GMT
  10. tzname: ('GMT', 'GMT')
  11. Zone : 0 (0.0)
  12. DST : 0
  13. Time : Sun Aug 14 18:10:42 2016
  14. Europe/Amsterdam :
  15. TZ : Europe/Amsterdam
  16. tzname: ('CET', 'CEST')
  17. Zone : -3600 (-1.0)
  18. DST : 1
  19. Time : Sun Aug 14 20:10:42 2016


Обработка и форматирование времени

Функции strptime() и strftime() преобразуют struct_time в строковые представления значений времени и наоборот. Существует длинный список инструкций по форматированию для поддержки ввода и вывода в разных форматах. Полный список указан в документации библиотеки для модуля time.

В приведенном ниже примере Python time текущее время преобразуется из строки в экземпляр struct_time и обратно в строку:

  1. time_strptime.py
  2. import time
  3. def show_struct(s):
  4. print(' tm_year :', s.tm_year)
  5. print(' tm_mon :', s.tm_mon)
  6. print(' tm_mday :', s.tm_mday)
  7. print(' tm_hour :', s.tm_hour)
  8. print(' tm_min :', s.tm_min)
  9. print(' tm_sec :', s.tm_sec)
  10. print(' tm_wday :', s.tm_wday)
  11. print(' tm_yday :', s.tm_yday)
  12. print(' tm_isdst:', s.tm_isdst)
  13. now = time.ctime(1483391847.433716)
  14. print('Now:', now)
  15. parsed = time.strptime(now)
  16. print('nParsed:')
  17. show_struct(parsed)
  18. print('nFormatted:',
  19. time.strftime("%a %b %d %H:%M:%S %Y", parsed))


В примере с time strftime Python строка вывода не такая же, как и входная, так как день месяца имеет префикс с нулем:

  1. $ python3 time_strptime.py
  2.  
  3. Now: Mon Jan 2 16:17:27 2017
  4.  
  5. Parsed:
  6. tm_year : 2017
  7. tm_mon : 1
  8. tm_mday : 2
  9. tm_hour : 16
  10. tm_min : 17
  11. tm_sec : 27
  12. tm_wday : 0
  13. tm_yday : 2
  14. tm_isdst: -1
  15.  
  16. Formatted: Mon Jan 02 16:17:27 2017


Перевод статьи «time — Clock Time» дружной командой проекта Сайтостроение от А до Я.

 
MyTetra Share v.0.52
Яндекс индекс цитирования