timeit(缓存问题?)导致的结果不可靠(?)

2024-09-28 03:24:20 发布

您现在位置:Python中文网/ 问答频道 /正文

我对numpy和skimage中的某些操作的计时很感兴趣,但我偶尔会看到我的努力产生了奇怪的(不完全可复制的)结果。简单地说,有时timeit返回的结果与看起来相同的操作相差大约5倍。以下是设置:

import skimage
import numpy as np
import timeit

nrep = 16

def run_complement(img):
    def inner():
        skimage.util.invert(img)
    return inner

img = np.random.randint(0, 65535, (512, 512, 3), dtype='uint16')

下面是一个示例课程:

In [1]: %run python_timing_bug.py

In [2]: t = timeit.Timer(run_complement(img))

In [3]: t.repeat(nrep, number=1)
Out[3]: 
[0.0024439050030196086,
 0.0020311699918238446,
 0.00033007100864779204,
 0.0002889479947043583,
 0.0002851780009223148,
 0.0002851030003512278,
 0.00028487699455581605,
 0.00032116699730977416,
 0.00030912700458429754,
 0.0002877369988709688,
 0.0002840430097421631,
 0.00028515000303741544,
 0.00030791999597568065,
 0.00029302599432412535,
 0.00030723700183443725,
 0.0002916679950430989]

In [4]: t = timeit.Timer(run_complement(img))

In [5]: t.repeat(nrep, number=1)
Out[5]: 
[0.0006320849934127182,
 0.0004014919977635145,
 0.00030359599622897804,
 0.00029224599711596966,
 0.0002907510061049834,
 0.0002920039987657219,
 0.0002918920072261244,
 0.0003095199936069548,
 0.00029789700056426227,
 0.0002885590074583888,
 0.00040198900387622416,
 0.00037131100543774664,
 0.00040271600300911814,
 0.0003492849937174469,
 0.0003378120018169284,
 0.00029762100894004107]

In [6]: t = timeit.Timer(run_complement(img))

In [7]: t.repeat(nrep, number=1)
Out[7]: 
[0.00026428700948599726,
 0.00012682100350502878,
 7.380900206044316e-05,
 6.346100417431444e-05,
 6.29679998382926e-05,
 6.278700311668217e-05,
 6.320899410638958e-05,
 6.25409884378314e-05,
 6.262199894990772e-05,
 6.247499550227076e-05,
 6.293901242315769e-05,
 6.259800284169614e-05,
 6.285199197009206e-05,
 6.293600017670542e-05,
 6.309800664894283e-05,
 6.248900899663568e-05]

请注意,在最后一次运行中,最小时间约为0.6e-4,而之前的最小时间约为3e-4,比之前运行中测得的时间小约5倍。当这种情况发生时,并不完全可以预测

更快的时间对应于阵列的0.08ns/单元,考虑到我的i7-8850H CPU上的2.6GHz时钟每~0.4ns滴答一次,这似乎已经超出了可信性的极限(尽管多亏了SIMD,也许不能完全排除这种可能性)。我的理解是,这个操作是implemented as a subtraction,并且很可能被减少为按位操作,而不是由编译器进行。(因此,您确实希望这是快速的,但不能完全确定它应该是快速的,并且在这两种情况下,不可再现性都是有问题的。)

可能需要注意的是,数据总量是

In [15]: img.size * 2
Out[15]: 1572864

lshw报告我有384KB的一级缓存和1536KB的二级缓存:

In [16]: 384*1024
Out[16]: 393216

In [17]: 1536*1024
Out[17]: 1572864

因此,这一结果似乎可能受到二级缓存拟合的影响。(请注意,超快运行发生在第一次运行之后。)如果我增加图像的大小:

 img = np.random.randint(0, 65535, (2048, 2048, 3), dtype='uint16')

然后,我的结果看起来更具可复制性,并且与其他语言的结果更为一致,并快速实现了此操作

是否有人对正在发生的事情有更深的了解,以及如何最好地管理它


Tags: runinimportnumpynumberimgnp时间

热门问题