首页 > 解决方案 > 如何在python中取消优化内存访问?

问题描述

这可能没有用。这只是我为自己设定的挑战。

假设您有一个大数组。你能做些什么来使程序不能从缓存、缓存行预取或下一次内存访问只能在第一次访问完成后确定的事实中受益。

所以我们有我们的数组:

array = [0] * 10000000

如果您必须访问循环中的所有元素,那么取消优化内存访问的最佳方法是什么?想法是尽可能增加每个内存位置的访问时间

我不是在寻找一个建议在进行下一次访问之前做“其他事情”(这需要时间)的解决方案。这个想法实际上是尽可能地增加访问时间。我想我们必须以某种方式遍历数组(也许是随机的?我还在研究它)

标签: pythonmemory

解决方案


我没想到有任何区别,但实际上以随机顺序访问数字比按顺序或反向访问数字要慢得多(两者大致相同)。

>>> N = 10**5
>>> arr = [random.randint(0, 1000) for _ in range(N)]
>>> srt = list(range(N))
>>> rvd = srt[::-1]
>>> rnd = random.sample(srt, N)
>>> %timeit sum(arr[i] for i in srt)
10 loops, best of 5: 24.9 ms per loop
>>> %timeit sum(arr[i] for i in rvd)
10 loops, best of 5: 25.7 ms per loop
>>> %timeit sum(arr[i] for i in rnd)
10 loops, best of 5: 59.2 ms per loop

这似乎真的是随机性。只是无序访问索引,但使用模式,例如 as [0, N-1, 2, N-3, ...]or [0, N/2, 1, N/2+1, ...],与按顺序访问它们一样快:

>>> alt1 = [i if i % 2 == 0 else N - i for i in range(N)]
>>> alt2 = [i for p in zip(srt[:N//2], srt[N//2:]) for i in p]
>>> %timeit sum(arr[i] for i in alt1)
10 loops, best of 5: 24.5 ms per loop
>>> %timeit sum(arr[i] for i in alt2)
10 loops, best of 5: 24.1 ms per loop

有趣的是,仅仅迭代洗牌的索引(并sum像上面的数组一样计算它们)比对排序的索引执行相同的操作要慢,但没有那么多。在 和 之间的约 35 毫秒差异中srtrnd约 10 毫秒似乎来自迭代随机索引,而约 25 毫秒用于以随机顺序实际访问索引。

>>> %timeit sum(i for i in srt)
100 loops, best of 5: 19.7 ms per loop
>>> %timeit sum(i for i in rnd)
10 loops, best of 5: 30.5 ms per loop
>>> %timeit sum(arr[i] for i in srt)
10 loops, best of 5: 24.5 ms per loop
>>> %timeit sum(arr[i] for i in rnd)
10 loops, best of 5: 56 ms per loop

(运行 Linux 的相当旧的笔记本电脑上的 IPython 5.8.0 / Python 3.7.3)


推荐阅读