【问题标题】:Why does parsing a dict very occasionally take far longer than usual为什么偶尔解析字典需要比平时更长的时间
【发布时间】:2017-06-25 05:02:11
【问题描述】:

在处理一个相当大的 Python(3) 项目时,我遇到了这种奇怪的行为,即迭代字典会非常偶尔(

这是一个显示行为的非常小的示例:

    from time import perf_counter
    from statistics import mean

    d = {"1": 0}
    times = []

    for _ in range(1000000):
        start = perf_counter()
        d = {k: v for k, v in d.items()}
        diff = (perf_counter() - start) * 10e6
        if diff > 0:
           times.append(diff)

    print("Mean: {}".format(mean(times)))
    print("Max: {}".format(max(times)))

例如。运行一次,平均时间为 10.806199298240244 微秒,但最大时间为 31015.980057418346 微秒,比正常时间长约 3000 倍。

有没有办法可以避免这种行为,还是 Python 固有的?

编辑:使用 perf_counter() 而不是 datetime 进行计时

【问题讨论】:

  • FWIW,我不能说这种现象是否真实——但是,使用datetime.now() 来计时(尤其是这么小的东西)可能非常不准确。 timeit.default_timer 可能是开始了解这种现象的更好地方...
  • 尝试为测试禁用垃圾收集?

标签: python python-3.x dictionary optimization


【解决方案1】:

您提交的大多数字典创建操作只花费了几纳秒 - 并且被视为 0 微秒。因此,每一个有一些延迟的动作,即使延迟只有几微秒,都算作一个巨大的变化 - 每个0 结果都会降低平均值超出其范围。

此外,最大结果与其他结果高度不同(它们通常是由于 CPU 的问题) - 使用偏差可以清楚地显示差异,并标记正常结果的一般范围。


试试

from time import perf_counter
from statistics import mean, stdev

d = {"1": 0}
times = []

for _ in range(100000):
    start = perf_counter()
    d = {k: v for k, v in d.items()}
    diff = (perf_counter() - start) * 10e6
    if diff > 0:
        times.append(diff)

print("Mean: {}".format(mean(times)))
print("Stddev: {}".format(stdev(times)))
print("Max: {}".format(max(times)))

与使用 time.timedatetime.now 相比,您应该得到更少的极端差异 - 并且小得多的结果(另外,看看标准偏差):

Mean: 11.520527719010078
Stddev: 4.476865528640042
Max: 443.1869339160954

【讨论】:

  • time.perf_countertimeit.default_timer 可能应该用来代替 time.time。此外,使用timeit 来完成整个事情可能是一个好主意,因为它可以处理经常被遗忘的细节,例如关闭垃圾收集器(这很可能是这里几个长周期的罪魁祸首)。不幸的是,我不知道有一种方法可以为您提供实际结果的直方图...
  • @mgilson 我相信matplotlib可以
  • @mgilson 更改为 perf_counter - 结果更准确且更小。谢谢!
  • 这样做仍然给我一个平均值 12.971177314323826 和最大值 10578.632354736328,所以在最坏的情况下仍然比平均时间长一千倍。我同意大多数时候操作如此之快以至于时间不准确,我需要了解的只是随机事件需要更长的时间。
  • 实际上,即使使用您的代码并进行一百万次测试,您仍然会得到相同的行为,例如。平均值:11.52598847169429 最大值:39204.430067911744
猜你喜欢
  • 1970-01-01
  • 2022-01-24
  • 1970-01-01
  • 1970-01-01
  • 2022-06-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多