如何在Python中获得毫秒和微秒级的时间戳

How to get millisecond and microsecond-resolution timestamps in Python

本问题已经有最佳答案,请猛点这里访问。

我终于明白了这一点,我想分享这些知识,节省一些时间,所以请看下面我的答案。但是,我仍然需要Linux的答案,因此如果您知道,请回答,因为我答案中的代码仅适用于Windows。

更新:我也已经为Linux解决了这个问题,包括针对Python3.3之前的版本(例如:针对Raspberry PI),我已经在下面的答案中发布了我的新模块/代码。

我最初的问题是:如何在Python中获得毫秒和微秒分辨率的时间戳?我还想要类似于arduino的delay和delayMicroseconds()函数。

更新日期:2018年12月19日:请不要将此问题标记为副本,并在肯定没有答案的情况下说它在其他地方有答案。

这个问题几个月前被标记为这个问题的副本。请参见这里:enter image description here

它说,"这个问题已经有答案了。"不幸的是,这不是真的。几年前,我在问这个问题之前读了这些答案,但他们没有回答我的问题,也没有满足我的需要。它们同样不适用于我的问题,就像这里最被否决的答案一样,因为不幸的是,它是错误的,因为它依赖于time模块,而在python 3.3之前,该模块没有任何类型的保证解决方案:

请重新打开我的问题。它不是复制品。它没有其他问题的事先答案。已包含答案的链接问题依赖于time模块,甚至声明其解决方案无处不在。那里投票最多的答案引用了Windows分辨率,使用16毫秒的答案,比我在这里提供的答案(0.5美国分辨率)差32000倍。同样,我需要1 ms和1 us(或类似)分辨率,而不是16000 us分辨率。因此,它不是复制品。

谢谢你抽出时间。:)


对于Windows:这里是一个针对两个Linux(也适用于python 3.3之前版本)和Windows的完全功能模块:

函数和代码示例。功能包括:

  • 微()
  • 毫秒()
  • 删除()
  • 延迟微秒()

python代码模块:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
"""
GS_timing.py
-create some low-level Arduino-like millis() (milliseconds) and micros()
 (microseconds) timing functions for Python
By Gabriel Staples
http://www.ElectricRCAircraftGuy.com
-click"Contact me" at the top of my website to find my email address
Started: 11 July 2016
Updated: 13 Aug 2016

History (newest on top):
20160813 - v0.2.0 created - added Linux compatibility, using ctypes, so that it's compatible with pre-Python 3.3 (for Python 3.3 or later just use the built-in time functions for Linux, shown here: https://docs.python.org/3/library/time.html)
-ex: time.clock_gettime(time.CLOCK_MONOTONIC_RAW)
20160711 - v0.1.0 created - functions work for Windows *only* (via the QPC timer)

References:
WINDOWS:
-personal (C++ code): GS_PCArduino.h
1) Acquiring high-resolution time stamps (Windows)
   -https://msdn.microsoft.com/en-us/library/windows/desktop/dn553408(v=vs.85).aspx
2) QueryPerformanceCounter function (Windows)
   -https://msdn.microsoft.com/en-us/library/windows/desktop/ms644904(v=vs.85).aspx
3) QueryPerformanceFrequency function (Windows)
   -https://msdn.microsoft.com/en-us/library/windows/desktop/ms644905(v=vs.85).aspx
4) LARGE_INTEGER union (Windows)
   -https://msdn.microsoft.com/en-us/library/windows/desktop/aa383713(v=vs.85).aspx

-*****https://stackoverflow.com/questions/4430227/python-on-win32-how-to-get-
absolute-timing-cpu-cycle-count

LINUX:
-https://stackoverflow.com/questions/1205722/how-do-i-get-monotonic-time-durations-in-python


"""


import ctypes, os

#Constants:
VERSION = '0.2.0'

#-------------------------------------------------------------------
#FUNCTIONS:
#-------------------------------------------------------------------
#OS-specific low-level timing functions:
if (os.name=='nt'): #for Windows:
    def micros():
       "return a timestamp in microseconds (us)"
        tics = ctypes.c_int64()
        freq = ctypes.c_int64()

        #get ticks on the internal ~2MHz QPC clock
        ctypes.windll.Kernel32.QueryPerformanceCounter(ctypes.byref(tics))
        #get the actual freq. of the internal ~2MHz QPC clock
        ctypes.windll.Kernel32.QueryPerformanceFrequency(ctypes.byref(freq))  

        t_us = tics.value*1e6/freq.value
        return t_us

    def millis():
       "return a timestamp in milliseconds (ms)"
        tics = ctypes.c_int64()
        freq = ctypes.c_int64()

        #get ticks on the internal ~2MHz QPC clock
        ctypes.windll.Kernel32.QueryPerformanceCounter(ctypes.byref(tics))
        #get the actual freq. of the internal ~2MHz QPC clock
        ctypes.windll.Kernel32.QueryPerformanceFrequency(ctypes.byref(freq))

        t_ms = tics.value*1e3/freq.value
        return t_ms

elif (os.name=='posix'): #for Linux:

    #Constants:
    CLOCK_MONOTONIC_RAW = 4 # see <linux/time.h> here: https://github.com/torvalds/linux/blob/master/include/uapi/linux/time.h

    #prepare ctype timespec structure of {long, long}
    class timespec(ctypes.Structure):
        _fields_ =\
        [
            ('tv_sec', ctypes.c_long),
            ('tv_nsec', ctypes.c_long)
        ]

    #Configure Python access to the clock_gettime C library, via ctypes:
    #Documentation:
    #-ctypes.CDLL: https://docs.python.org/3.2/library/ctypes.html
    #-librt.so.1 with clock_gettime: https://docs.oracle.com/cd/E36784_01/html/E36873/librt-3lib.html #-
    #-Linux clock_gettime(): http://linux.die.net/man/3/clock_gettime
    librt = ctypes.CDLL('librt.so.1', use_errno=True)
    clock_gettime = librt.clock_gettime
    #specify input arguments and types to the C clock_gettime() function
    # (int clock_ID, timespec* t)
    clock_gettime.argtypes = [ctypes.c_int, ctypes.POINTER(timespec)]

    def monotonic_time():
       "return a timestamp in seconds (sec)"
        t = timespec()
        #(Note that clock_gettime() returns 0 for success, or -1 for failure, in
        # which case errno is set appropriately)
        #-see here: http://linux.die.net/man/3/clock_gettime
        if clock_gettime(CLOCK_MONOTONIC_RAW , ctypes.pointer(t)) != 0:
            #if clock_gettime() returns an error
            errno_ = ctypes.get_errno()
            raise OSError(errno_, os.strerror(errno_))
        return t.tv_sec + t.tv_nsec*1e-9 #sec

    def micros():
       "return a timestamp in microseconds (us)"
        return monotonic_time()*1e6 #us

    def millis():
       "return a timestamp in milliseconds (ms)"
        return monotonic_time()*1e3 #ms

#Other timing functions:
def delay(delay_ms):
   "delay for delay_ms milliseconds (ms)"
    t_start = millis()
    while (millis() - t_start < delay_ms):
      pass #do nothing
    return

def delayMicroseconds(delay_us):
   "delay for delay_us microseconds (us)"
    t_start = micros()
    while (micros() - t_start < delay_us):
      pass #do nothing
    return

#-------------------------------------------------------------------
#EXAMPLES:
#-------------------------------------------------------------------
#Only executute this block of code if running this module directly,
#*not* if importing it
#-see here: http://effbot.org/pyfaq/tutor-what-is-if-name-main-for.htm
if __name__ =="__main__": #if running this module as a stand-alone program

    #print loop execution time 100 times, using micros()
    tStart = micros() #us
    for x in range(0, 100):
        tNow = micros() #us
        dt = tNow - tStart #us; delta time
        tStart = tNow #us; update
        print("dt(us) =" + str(dt))

    #print loop execution time 100 times, using millis()
    print("
"
)
    tStart = millis() #ms
    for x in range(0, 100):
        tNow = millis() #ms
        dt = tNow - tStart #ms; delta time
        tStart = tNow #ms; update
        print("dt(ms) =" + str(dt))

    #print a counter once per second, for 5 seconds, using delay
    print("
start"
)
    for i in range(1,6):
        delay(1000)
        print(i)

    #print a counter once per second, for 5 seconds, using delayMicroseconds
    print("
start"
)
    for i in range(1,6):
        delayMicroseconds(1000000)
        print(i)

如果您知道如何在Linux中获得上述毫秒和微秒分辨率时间戳,请发布,因为这也将非常有用。

这也适用于Linux,包括Python3.3之前的版本,因为我通过ctypes模块使用C函数来读取时间戳。

(注:以上代码最初发布在这里:http://www.electrircaircraftguy.com/2016/07/arduino-like-millisecond-and-microsecond-timestamps-in-python.html)

特别感谢@arminronacher为他出色的python 3.3之前的linux提供的答案:https://stackoverflow.com/a/1205762/4561877

更新:在python3.3之前,内置的python时间库(https://docs.python.org/3.5/library/time.html)没有任何显式的高分辨率函数。不过,现在它提供了其他选项,包括一些高分辨率功能。

不过,上面的模块为python3.3之前和之后的python代码提供了高分辨率的时间戳,在Linux和Windows上都是如此。

这是我的意思的一个例子,表明time.sleep()函数不一定是高分辨率函数。*在我的Windows机器上,它的分辨率最多可能是8毫秒,而我上面的模块的分辨率是0.5us(16000倍更好!)在同一台机器上。

代码演示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import time
import GS_timing as timing

def delayMicroseconds(n):
    time.sleep(n / 1000000.)

def delayMillisecond(n):
    time.sleep(n / 1000.)

t_start = 0
t_end = 0

#using time.sleep
print('using time.sleep')
print('delayMicroseconds(1)')
for x in range(10):
    t_start = timing.micros() #us
    delayMicroseconds(1)
    t_end = timing.micros() #us
    print('dt (us) = ' + str(t_end - t_start))
print('delayMicroseconds(2000)')
for x in range(10):
    t_start = timing.micros() #us
    delayMicroseconds(2000)
    t_end = timing.micros() #us
    print('dt (us) = ' + str(t_end - t_start))

#using GS_timing
print('
using GS_timing'
)
print('timing.delayMicroseconds(1)')
for x in range(10):
    t_start = timing.micros() #us
    timing.delayMicroseconds(1)
    t_end = timing.micros() #us
    print('dt (us) = ' + str(t_end - t_start))
print('timing.delayMicroseconds(2000)')
for x in range(10):
    t_start = timing.micros() #us
    timing.delayMicroseconds(2000)
    t_end = timing.micros() #us
    print('dt (us) = ' + str(t_end - t_start))

我的Windows 8.1计算机上的示例结果(请注意,time.sleep的情况更糟):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
using time.sleep
delayMicroseconds(1)
dt (us) = 2872.059814453125
dt (us) = 886.3939208984375
dt (us) = 770.4649658203125
dt (us) = 1138.7698974609375
dt (us) = 1426.027099609375
dt (us) = 734.557861328125
dt (us) = 10617.233642578125
dt (us) = 9594.90576171875
dt (us) = 9155.299560546875
dt (us) = 9520.526611328125
delayMicroseconds(2000)
dt (us) = 8799.3056640625
dt (us) = 9609.2685546875
dt (us) = 9679.5439453125
dt (us) = 9248.145263671875
dt (us) = 9389.721923828125
dt (us) = 9637.994262695312
dt (us) = 9616.450073242188
dt (us) = 9592.853881835938
dt (us) = 9465.639892578125
dt (us) = 7650.276611328125

using GS_timing
timing.delayMicroseconds(1)
dt (us) = 53.3477783203125
dt (us) = 36.93310546875
dt (us) = 36.9329833984375
dt (us) = 34.8812255859375
dt (us) = 35.3941650390625
dt (us) = 40.010986328125
dt (us) = 38.4720458984375
dt (us) = 56.425537109375
dt (us) = 35.9072265625
dt (us) = 36.420166015625
timing.delayMicroseconds(2000)
dt (us) = 2039.526611328125
dt (us) = 2046.195068359375
dt (us) = 2033.8841552734375
dt (us) = 2037.4747314453125
dt (us) = 2032.34521484375
dt (us) = 2086.2059326171875
dt (us) = 2035.4229736328125
dt (us) = 2051.32470703125
dt (us) = 2040.03955078125
dt (us) = 2027.215576171875

我的Raspberry PI版本1b+上的示例结果(注意,在使用time.sleep和我的模块之间的结果基本相同……显然,time中的低级功能已经访问了更好的分辨率计时器,因为它是一台Linux机器(运行Raspbian)…但是在我的GS_timing模块中,我明确地调用了时钟-单调-原始计时器。谁知道别人在用什么):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
using time.sleep
delayMicroseconds(1)
dt (us) = 1022.0
dt (us) = 417.0
dt (us) = 407.0
dt (us) = 450.0
dt (us) = 2078.0
dt (us) = 393.0
dt (us) = 1297.0
dt (us) = 878.0
dt (us) = 1135.0
dt (us) = 2896.0
delayMicroseconds(2000)
dt (us) = 2746.0
dt (us) = 2568.0
dt (us) = 2512.0
dt (us) = 2423.0
dt (us) = 2454.0
dt (us) = 2608.0
dt (us) = 2518.0
dt (us) = 2569.0
dt (us) = 2548.0
dt (us) = 2496.0

using GS_timing
timing.delayMicroseconds(1)
dt (us) = 572.0
dt (us) = 673.0
dt (us) = 1084.0
dt (us) = 561.0
dt (us) = 728.0
dt (us) = 576.0
dt (us) = 556.0
dt (us) = 584.0
dt (us) = 576.0
dt (us) = 578.0
timing.delayMicroseconds(2000)
dt (us) = 2741.0
dt (us) = 2466.0
dt (us) = 2522.0
dt (us) = 2810.0
dt (us) = 2589.0
dt (us) = 2681.0
dt (us) = 2546.0
dt (us) = 3090.0
dt (us) = 2600.0
dt (us) = 2400.0


1
2
3
4
5
6
7
import time

def delayMicroseconds(n):
    time.sleep(n / 1000000.)

def delayMillisecond(n):
    time.sleep(n / 1000.)

另请参见:如何在python中进行时间延迟?