我正在阅读question,我想更多地询问他所展示的代码,即
for(i = 0; i < 20; i++)
for(j = 0; j < 10; j++)
a[i] = a[i]*j;
问题是,
这个人说,
“访问[i]十时,内部循环将调用相同的内存地址 我想这是时间局部性的一个例子。但是有吗 空间局部性也在上面的循环中?“
我不同意他的猜测。作为[i]生成的引用 应该是空间位置(他们将引用下一个 块中的元素)。我是对的吗?
答案 0 :(得分:22)
首先,对var
的引用可以是暂时本地或空间本地而非时间位置,这是不正确的语法。小点。
现在,问你的问题。
时间位置的原则指出两条指令在相对较短的时间范围内引用相同的位置。例如,在给定的代码中,a[i]
经常被引用,a[i] = a[i] * 2
和a[i] = a[i] * 3
等指令的执行非常接近。如果我们正在查看此范围,我们可以说对j
和a[i]
的引用暂时是本地的。对i
的引用也暂时是本地的,因为每次i
都会引用a[i]
。但是,如果给定代码的最后一行读取a[j] = a[j] * j
之类的内容,则对i
的引用不会在时间上是局部的,至少在内部循环的范围内 [1] 。
空间位置的原则指出两条指令引用连续的内存位置。对a[i]
的引用就是一个很好的例子,因为人们可以假设(大部分时间)a[0]
和a[1]
在内存中彼此相邻。
前两个基本涵盖了这一点,但引用的文字是正确的,代码也展示了空间位置。
[1] - 通常,当你谈论局部性时,它将在内存层次结构中的给定级别的上下文中,无论是RAM还是L1缓存或者你有什么。除了最有限的意义外,对i
和j
的引用暂时是本地的。
答案 1 :(得分:3)
写这个答案是因为即使在阅读了有关该问题的其他答案,其他一些问题和维基百科之后,我还是没有得到答案(这更加令人困惑。)
我认为我们花费大量时间和精力来理解术语,在这种情况下有点令人困惑/复杂。当我不注意“空间”和“时间”时,我发现更容易理解。
让我们从基础开始。
让我们尝试了解高速缓存是什么-比主内存访问速度更快的地方。这很酷。但是这个地方是有限和昂贵的,因此应该明智地使用它。但是,您(或OS)将如何决定将哪些内容放入缓存中以及不放入哪些内容?应该有某种方式可以知道我们将来需要什么。.未来的预测! (少数派报告!敲钟?)。
应该有某种方法来确定程序将来需要什么。使用常识和代码,我们可以说代码的某些部分本质上是重复的,例如循环!如果循环中有一个变量i,那么您将在不久的将来一次又一次地访问它。这是时间局部性的原理。我可以进入缓存,因为它在时间上是本地的。
在另一个区域中,如果代码使用任何线性数据结构(例如:数组),并且在循环中也使用索引增量,那么很容易看到,尽管当前的需求仅是第三个位置(对于(例如)该数据结构,很快将需要下一个位置,因为该线性数据结构的索引增加了1。因此,如果我们也能在接下来的几个位置引入数据,那就太好了。这是空间局部性的原理。由于接下来的几个位置是局部本地的,因此可以将其放入缓存。
局部性的概念基本上是识别要引入缓存的数据和指令,以便我们可以减少缓存未命中并有效利用此特殊位置。
答案 2 :(得分:2)
外环是空间局部性的一个例子。它按顺序递增内部for循环调用的地址。
内部循环展示了时间局部性。连续十次访问完全相同的内存地址,每次乘以j。
至于你的前两个问题,i和j(循环计数器)都是时间局部性的非常好的例子。
Locality是缓存应用的一种度量,用于最小化对内存的调用。如果指令需要知道缓存中尚未存在的存储器地址的值,它将访问存储器并将所有周围的存储器位置存储在缓存中。
答案 3 :(得分:2)
让我们先定义时间和空间位置。
时间局部性-时间局部性意味着可能很快需要获取当前的数据或指令。因此,我们应该将该数据或指令存储在高速缓存中,以免再次在主存储器中搜索相同的数据,从而节省时间。
空间局部性-空间局部性是指在不久的将来可能需要接近正在获取的当前存储位置的指令或数据。
sum = 0;
for (i = 0; i < arr.length; i++)
sum += arr[i];
return sum;
现在看这个例子,这里反复使用变量sum,它显示临时位置,然后按顺序访问数组arr的值,即arr [0],arr [1 ],arr [2]等...,它们显示空间局部性,因为数组是连续(相邻)存储块,因此正在读取当前存储位置附近的数据拿来。
现在看这个例子
for(i = 0; i < 20; i++)
for(j = 0; j < 10; j++)
a[i] = a[i]*j;
在这里,我们看到时间局部性,因为第二次循环中的a [i]被一次又一次地使用,然后依次访问变量j,以显示空间局部性。