Python模块操作:time—Clock Time

Python模块操作:time—Clock Time

目的:操作时钟的函数

时间模块提供几种不同类型时钟的访问途径,每种都用于不同的目的。标准系统调用像time()报告系统"挂钟"时间。monotonic()时钟函数被用来测量在长期进程中经过的时间,因为它确保时间永不往回走,即使系统时间被改变。对于性能测试,perf_counter()函数提供获取具有最高解析度的时钟访问,使短时间测量更精确。CPU时间通过clock()函数可以获取,并且process_time()函数返回处理器时间和系统时间的组合。

注意

这些实现公开了操作时间和日期的C库函数。由于它们绑定到底层C实现,因此一些细节(例如时间纪元的开始和支持的最大日期值)是限于特定的平台。可以参照库文档了解全部的细节。

比较的时钟

实现的细节根据平台而变化。使用get_clock_info()访问有关当前实现的基本信息,包括时钟的分辨率。

import textwrap
import time

available_clocks = [
    ('monotonic', time.monotonic),
    ('perf_counter', time.perf_counter),
    ('process_time', time.process_time),
    ('time', time.time),
]

for clock_name, func in available_clocks:
    print(textwrap.dedent('''\
    {name}:
        adjustable : {info.adjustable}
        implementation: {info.implementation}
        monotonic: {info.monotonic}
        resolution: {info.resolution}
        current: {current}
        ''').format(
        name=clock_name,
        info=time.get_clock_info(clock_name),
        current=func()
    ))


以下是macOS系统的输出,展示了monotonic和perf_counter时钟的执行是使用相同的系统调用。

monotonic:
    adjustable : False
    implementation: mach_absolute_time()
    monotonic: True
    resolution: 1e-09
    current: 0.94656131

perf_counter:
    adjustable : False
    implementation: mach_absolute_time()
    monotonic: True
    resolution: 1e-09
    current: 0.946618741

process_time:
    adjustable : False
    implementation: clock_gettime(CLOCK_PROCESS_CPUTIME_ID)
    monotonic: True
    resolution: 1.0000000000000002e-06
    current: 0.824873

time:
    adjustable : True
    implementation: clock_gettime(CLOCK_REALTIME)
    monotonic: False
    resolution: 1.0000000000000002e-06
    current: 1671860901.9184608


Process finished with exit code 0

win10系统的输出结果如下图:

12

挂钟时间

时间模块的一个核心函数就是time(),这个函数返回纪元开始浮点类型的秒数值。

import time
print('the time is: ',  time.time())

纪元是时间测量的起始,对于Unix系统是0:00, 1970年1月1日。尽管值总是浮点型的,实际的精度还有赖于平台。

macOS系统的输出结果如下:

/usr/local/bin/python3.9 /Users/bruce_liu/wall_clock_time.py
the time is:  1671863148.7370439

win10系统的输出结果如下图:

13

当日期用于存储和比较的时候,浮点表示是有用的,但是在生成人类可读的表示来说,用处不大。

对于记录或者打印时间ctime()可能更有用。

import time
print('The time is    :', time.ctime())
later = time.time() + 15
print('15 secs from now: ', time.ctime(later))

第2个print()函数在这个例子里的调用表明如何使用ctime()格式化一个时间值而不是当前时间。

macOS系统运行结果如下:

The time is    : Sat Dec 24 14:52:24 2022
15 secs from now:  Sat Dec 24 14:52:39 2022

Process finished with exit code 0

单调的时钟

因为time()函数查看系统时间,并且系统时钟可以由用户或者系统服务修改,以便在多台计算机上同步时钟,重复地调用time()函数可能产生向前和向后的值。当试图测量时间段或者用那些时间计算的时候,这可能导致不期望的行为。为了避免那些情形,要通过使用monotonic()函数,这个函数返回值总是向前的。

import time

start = time.monotonic()
time.sleep(0.1)
end = time.monotonic()
print('start :  {:>9.2f}'.format(start))
print('end   :  {:>9.2f}'.format(end))
print('span  :  {:>9.2f}'.format(end - start))

macOS系统运行结果如下:

start :       0.45
end   :       0.56
span  :       0.10

win10系统运行结果如下图:

14

处理器时钟时间

当time()函数返回一个挂钟时间,process_time()函数返回处理器时钟时间。这个来自process_time()函数的返回值反应的是当程序运行时使用的实际时间。

import hashlib
import time

# data用来计算md5校验和
data = open(__file__, 'rb').read()

for i in range(5):
    h = hashlib.sha1()
    print(time.ctime(), ': {:0.3f} {:0.3f}'.format(time.time(),
                                                   time.process_time()))

    for i in range(300000):
        h.update(data)
    cksum = h.digest()

本示例中,格式化的ctime()与来自time()和clock()函数每次循环迭代的浮点值也一起被打印出来。

mac OS系统运行结果如下:

Sat Dec 24 15:34:24 2022 : 1671867264.858 0.851
Sat Dec 24 15:34:25 2022 : 1671867265.055 1.043
Sat Dec 24 15:34:25 2022 : 1671867265.258 1.241
Sat Dec 24 15:34:25 2022 : 1671867265.449 1.428
Sat Dec 24 15:34:25 2022 : 1671867265.629 1.607

注意

如果您希望在您的系统上运行这个示例,您可能必须向内循环添加更多的循环,或者处理更大量的数据,才能真正看到时间上的差异。

通常,如果程序不执行任何操作,处理器时钟就不会滴答作响。

import time

template = '{} - {:0.2f} - {:0.2f}'

print(template.format(
    time.ctime(), time.time(), time.process_time()
))

for i in range(3, 0, -1):
    print('Sleeping', i)
    time.sleep(i)
    print(template.format(
        time.ctime(), time.time(), time.process_time()
    ))

在本例中,循环在每次迭代之后进入睡眠状态,只做很少工作。即使应用程序进入休眠状态,time()值也会增加,但process_time()值不会。macOS系统运行结果如下:

Sat Dec 24 15:54:31 2022 - 1671868471.45 - 0.81
Sleeping 3
Sat Dec 24 15:54:34 2022 - 1671868474.45 - 0.81
Sleeping 2
Sat Dec 24 15:54:36 2022 - 1671868476.45 - 0.81
Sleeping 1
Sat Dec 24 15:54:37 2022 - 1671868477.46 - 0.81

调用sleep()函数会释放当前线程的控制权,并要求它等待系统将其唤醒。如果一个程序只有一个线程,这有效地阻塞了app而且它不工作。

性能计数器

有一个高解析度的单调时钟来测量性能是很重要的。确定最佳时钟数据源需要特定平台知识,Python在perf_counter()函数里提供了这些。

import hashlib
import time


# data用于计算md5校验和
data = open(__file__, 'rb').read()

loop_start = time.perf_counter()

for i in range(5):
    iter_start = time.perf_counter()
    h = hashlib.sha1()
    for i in range(300000):
        h.update(data)
        
    cksum = h.digest()
    now = time.perf_counter()
    loop_elapsed = now - loop_start
    iter_elapsed = now - iter_start
    print(time.ctime(), ': {:0.3f} {:0.3f}'.format(
        iter_elapsed, loop_elapsed
    ))

与monotonic()函数一样,perf_counter()的纪元是未定义的,这些值将用于比较和计算值,而不是绝对的时间。

macOS系统运行结果如下:

Sat Dec 24 16:12:45 2022 : 0.221 0.221
Sat Dec 24 16:12:45 2022 : 0.240 0.461
Sat Dec 24 16:12:45 2022 : 0.199 0.660
Sat Dec 24 16:12:45 2022 : 0.219 0.879
Sat Dec 24 16:12:45 2022 : 0.221 1.100

时间组件

时间存储为经过的秒数在某些场合是有用的,但是有时候程序需要获取日期的各个字段(年,月等)。time模块定义了struct_time 用于保存日期和时间值,并将组建分开,便于访问。有几个函数用结构时间值而不是浮点数。

import time

def show_struct(s):
    print('  tm_year :', s.tm_year)
    print('  tm_mon :', s.tm_mon)
    print('  tm_mday :', s.tm_mday)
    print('  tm_hour :', s.tm_hour)
    print('  tm_min  :', s.tm_min)
    print('  tm_sec  :', s.tm_sec)
    print('  tm_wday :', s.tm_wday)
    print('  tm_yday :', s.tm_yday)
    print('  tm_isdst:', s.tm_isdst)

    
print('gmtime:')
show_struct(time.gmtime())

print('\nlocaltime:')
show_struct(time.localtime())
print('\nmktime:', time.mktime(time.localtime()))

这个gmtime()函数返回当前UTC时间。localtime()返回当前应用的时区的当前时间。mktime()接受一个struct_time并且转换成浮点型表示。

macOS系统运行结果如下:


gmtime:
  tm_year : 2022
  tm_mon : 12
  tm_mday : 24
  tm_hour : 9
  tm_min  : 0
  tm_sec  : 16
  tm_wday : 5
  tm_yday : 358
  tm_isdst: 0

localtime:
  tm_year : 2022
  tm_mon : 12
  tm_mday : 24
  tm_hour : 17
  tm_min  : 0
  tm_sec  : 16
  tm_wday : 5
  tm_yday : 358
  tm_isdst: 0

mktime: 1671872416.0

使用时区

确定当前时间的函数依赖于通过程序或使用系统的默认时区设置时区。更改时区并不会改变实际时间,只会改变表时间的方式。要更改时区,请设置环境变量TZ,然后调用tzset()函数。可以通过许多细节指定时区,精确到夏令时的开始和停止时间。不过,使用时区名称并让底层库派生其他信息通常更容易。

这个示例将时区更改为几个不同的值,并显示这些更改如何影响时间模块中的其他设置。

import time
import os

def show_zone_info():
    print('  TZ   :', os.environ.get('TZ', '(not set)'))
    print('  tzname:', time.tzname)
    print('  Zone  : {} ({})'.format(
        time.timezone, (time.timezone / 3600)
    ))
    print('  DST  :', time.daylight)
    print('  Time :', time.ctime())
    print()

print('Default:')
show_zone_info()

ZONES = [
    'GMT',
    'Europe/Amsterdam',
]

for zone in ZONES:
    os.environ['TZ'] = zone
    time.tzset()
    print(zone, ':')
    show_zone_info()

系统用于准备示例的默认时区是CST。示例中的其他区域更改tzname,日光标志和时区偏移值。

在macOS系统运行结果如下:

Default:
  TZ   : (not set)
  tzname: ('CST', 'CST')
  Zone  : -28800 (-8.0)
  DST  : 0
  Time : Sat Dec 24 17:44:57 2022

GMT :
  TZ   : GMT
  tzname: ('GMT', 'GMT')
  Zone  : 0 (0.0)
  DST  : 0
  Time : Sat Dec 24 09:44:57 2022

Europe/Amsterdam :
  TZ   : Europe/Amsterdam
  tzname: ('CET', 'CEST')
  Zone  : -3600 (-1.0)
  DST  : 1
  Time : Sat Dec 24 10:44:57 2022

解析和格式化时间

两个函数strptime()和strftime()在时间值的结构时间和字符表示之间进行转换。有一个很长的格式说明列表,用于支持不同样式的输入和输出。完整的列表记录在time模块的库文档中。

此示例将当前时间从字符串转换为struct时间实例,然后再转换回字符串。

import time

def show_struct(s):
    print('  tm_year  :', s.tm_year)
    print('  tm_mon   :', s.tm_mon)
    print('  tm_mday  :', s.tm_mday)
    print('  tm_hour  :', s.tm_hour)
    print('  tm_min   :', s.tm_min)
    print('  tm_sec   :', s.tm_sec)
    print('  tm_wday  :', s.tm_wday)
    print('  tm_yday  :', s.tm_yday)
    print('  tm_isdst  :', s.tm_isdst)


now = time.ctime(1383391847.433716)
print('Now: ', now)

parsed = time.strptime(now)
print('\nParsed:')
show_struct(parsed)
print('\nFormatted:',
      time.strftime('%a %b %d %H:%M:%S %Y', parsed))

输出字符串与输入不完全相同,因为月份的日期前缀是0

macOS系统输出结果如下:

Now:  Sat Nov  2 19:30:47 2013

Parsed:
  tm_year  : 2013
  tm_mon   : 11
  tm_mday  : 2
  tm_hour  : 19
  tm_min   : 30
  tm_sec   : 47
  tm_wday  : 5
  tm_yday  : 306
  tm_isdst  : -1

Formatted: Sat Nov 02 19:30:47 2013
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值