这几乎和它得到的一样好,因为C 模块(如果可用)使用快速 C 实现覆盖在 datetime 模块的纯 Python 实现中定义的所有类,并且有没有钩子。
参考:python/cpython@cf86e36
注意:
- 在精度中存在一个固有的亚微秒级误差,它等于在
datetime.now() 中获取系统时间与获取性能计数器时间之间所用的时间。
- 添加
datetime 和timedelta 会产生亚微秒级的性能成本。
根据您的具体用例是否多次调用,这可能会或可能不会重要。
稍有改进:
INITIAL_TIMESTAMP: Final[float] = time.time()
INITIAL_TIMESTAMP_PERF_COUNTER: Final[float] = time.perf_counter()
def get_timestamp_float() -> float:
dt_sec = time.perf_counter() - INITIAL_TIMESTAMP_PERF_COUNTER
return INITIAL_TIMESTAMP + dt_sec
def get_timestamp_now() -> datetime:
dt_sec = time.perf_counter() - INITIAL_TIMESTAMP_PERF_COUNTER
return datetime.fromtimestamp(INITIAL_TIMESTAMP + dt_sec)
轶事数字
窗户:
# Intrinsic error
timeit.timeit('datetime.now()', setup='from datetime import datetime')/1000000 # 0.31 μs
timeit.timeit('time.time()', setup='import time')/1000000 # 0.07 μs
# Performance cost
setup = 'from datetime import datetime, timedelta; import time'
timeit.timeit('datetime.now() + timedelta(1.000001)', setup=setup)/1000000 # 0.79 μs
timeit.timeit('datetime.fromtimestamp(time.time() + 1.000001)', setup=setup)/1000000 # 0.44 μs
# Resolution
min get_timestamp_float() delta: 239 ns
Windows 和 macOS:
|
Windows |
macOS |
| # Intrinsic error |
|
|
timeit.timeit('datetime.now()', setup='from datetime import datetime')/1000000 |
0.31 μs |
0.61 μs |
timeit.timeit('time.time()', setup='import time')/1000000 |
0.07 μs |
0.08 μs |
| # Performance cost |
|
|
setup = 'from datetime import datetime, timedelta; import time' |
- |
- |
timeit.timeit('datetime.now() + timedelta(1.000001)', setup=setup)/1000000 |
0.79 μs |
1.26 μs |
timeit.timeit('datetime.fromtimestamp(time.time() + 1.000001)', setup=setup)/1000000 |
0.44 μs |
0.69 μs |
| # Resolution |
|
|
min time() delta (benchmark) |
x ms |
716 ns |
min get_timestamp_float() delta |
239 ns |
239 ns |
239 ns 是 float 在 Unix 时间量级上允许的最小差异,正如 cmets 中的 Kelly Bundy 所指出的那样。
x = time.time()
print((math.nextafter(x, 2*x) - x) * 1e9) # 238.4185791015625
脚本
解析脚本,基于https://www.python.org/dev/peps/pep-0564/#script:
import math
import time
from typing import Final
LOOPS = 10 ** 6
INITIAL_TIMESTAMP: Final[float] = time.time()
INITIAL_TIMESTAMP_PERF_COUNTER: Final[float] = time.perf_counter()
def get_timestamp_float() -> float:
dt_sec = time.perf_counter() - INITIAL_TIMESTAMP_PERF_COUNTER
return INITIAL_TIMESTAMP + dt_sec
min_dt = [abs(time.time() - time.time())
for _ in range(LOOPS)]
min_dt = min(filter(bool, min_dt))
print("min time() delta: %s ns" % math.ceil(min_dt * 1e9))
min_dt = [abs(get_timestamp_float() - get_timestamp_float())
for _ in range(LOOPS)]
min_dt = min(filter(bool, min_dt))
print("min get_timestamp_float() delta: %s ns" % math.ceil(min_dt * 1e9))