立即停止用 time() 来测试 python 中函数的性能

文章讨论了在Python中使用time.time()函数衡量任务性能的不足,因为它依赖于可调整的系统时钟。文章建议使用time.monotonic()和time.perf_counter(),这两个函数提供更高精度和线性时钟,适合性能测试。通过示例和滴答率比较,展示了perf_counter()在测量短时间间隔上的优势。
摘要由CSDN通过智能技术生成

如果你习惯于使用 time.time() 函数而不是 time.monotonic() 或 time.perf_counter() 来衡量 Python 中任务的性能,而且想知道为什么,那么这篇文章就是为你准备的。

首先我们导入模块:

improt time

先来个简单的例子

为了简单起见,假设你的任务是计算二维数组中某个值的出现次数,但是你不满足于仅仅这样做,你还想衡量这样做所花费的时间,代码实现如下:

def count_value(array, value):
   c = 0
   t_start = time.time()
   for i in array:
       for j in i:
           if j == value:
               c += 1
   t_end = time.time()

   return c, t_end-t_start

现在让我们在一些数组上使用这个函数:

a_1 = [[1,2],[3,3]]
a_2 = [[33]]
a_3 = [[1 for _ in range(10)] for _ in range(100)]
a_4 = [[i*j for j in range(1000)] for i in range(1000)]

print(count_value(a_1, 3))
print(count_value(a_2, 10))
print(count_value(a_3, 1))
print(count_value(a_4, 44))

输出:

(2, 0.0)
(0, 0.0)
(1000, 0.0)
(6, 0.03124070167541504)

现在在讨论实际问题之前,我建议使用装饰器来衡量函数的性能,但这超出了本文的范围,后续再写一篇单独说。那我们来谈谈上面这些问题。在 4 个数组中的 3 个上,我们看到为搜索测量的时间为 0,这意味着搜索是即时的,其实不是,这里的问题是 time.time() 函数使用系统时钟,这有几个问题:

  • 这个时钟的滴答率不够小,如果在时钟的两个“滴答”之间执行任务,我们将无法测量任务的实际长度,因为它会比时钟的分辨率短

  • 系统时钟可以通过外部因素进行修改,例如更新、时钟校准或闰秒。

为了解决这些问题,时间库有 2 个函数:monotonic() 和 perf_counter(或者如果我们还考虑纳秒替代方案,则有 4 个函数:monotonic_ns() 和 perf_counter_ns())。

重要的是要知道这些函数解决了这两个问题:Monotonic() 函数基于线性时钟,无法从外部修改,而 perf_counter() 函数具有更高的滴答率。

显示滴答率差异

让我们编写一个函数来显示所有三个函数的不同滴答率:time()、monotonic() 和 perf_counter。我将使用 perf_counter_ns() 来测量经过的时间。

def tick_rate(f):
   tick = 0
   t_start = time.perf_counter_ns()
   last_t = f()
   for i in range(10_000_000):
       t = f()
       if t != last_t:
           tick += 1
       last_t = t
   t_end = time.perf_counter_ns()

   return tick, (t_end-t_start)/(10**9) #divided by 10^9 to convert ns to s

print(tick_rate(time.time))
print(tick_rate(time.monotonic))
print(tick_rate(time.perf_counter))

输出:

(59, 0.9173757)
(50, 0.7825792)
(10000000, 1.615493)

现在我们可以看到使用 perf_counter() 函数测量小任务的能力的巨大差异,事实上,我们无法测量 perf_counter() 使用的时钟的最大滴答率,但它仍然很大 . monotonic() 函数可用于更长的任务。

相同的例子使用perf_counter()让我们使用与之前相同的示例,但使用 perf_counter() 而不是 time():

def count_value(array, value):
   c = 0
   t_start = time.perf_counter()
   for i in array:
       for j in i:
           if j == value:
               c += 1
   t_end = time.perf_counter()

   return c, t_end-t_start

a_1 = [[1,2],[3,3]]
a_2 = [[33]]
a_3 = [[1 for _ in range(10)] for _ in range(100)]
a_4 = [[i*j for j in range(1000)] for i in range(1000)]

print(count_value(a_1, 3))
print(count_value(a_2, 10))
print(count_value(a_3, 1))
print(count_value(a_4, 44))

输出:

(2, 4.7999997150327545e-06)
(0, 1.4000002011016477e-06)
(1000, 7.83999998930085e-05)
(6, 0.036078900000120484)

如上我们所看到的,我们实际上能够通过使用正确的函数来测量所花费的时间。

在我的下一篇文章中,我将讨论装饰器以及为什么在测量函数的性能时它们很适合使用。如果你读到了文章的结尾,请考虑订阅我的时事通讯,它是免费的,让我保持动力!

原文:https://www.raaicode.com/using-time-monotonic-and-perf_counter-to-measure-time-in-python/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值