我理解这些术语的定义,但是我在将它们的概念应用于代码时遇到了麻烦。对于练习,我们被要求描述以下代码是空间的还是时间的:
for (int i=0; i<10; i++) {
printf(some_array[i]);
}
我觉得这是空间局部性,因为当访问数组的一个索引时,一旦循环迭代,就会访问下一个索引内存位置。这是看待它的正确方法吗?是什么决定了代码是时间还是空间?更多的例子会很棒。
答案 0 :(得分:11)
这真是一个愚蠢的运动。代码不是时间或空间的。
但是时间局部性意味着您将多次访问同一地址,并且时间相对接近。你在这里没有这样做(除非你计算访问i
,我猜),所以通过一个消除过程,你可以得出结论,这必须是空间局部性。
更准确地说,您正在访问some_array[0]
,然后some_array[1]
等等。这些在地址空间中非常接近,所以是的,这可能是“依赖”空间< / em> locality。
答案 1 :(得分:5)
在通常出现这些概念的硬件高速缓存存储器的上下文中,分析通常不是基于存储器地址进行的,可以这么说。通过访问内存块来分析位置,这些内存块是在缓存和主内存之间传输的。
如果您这样想,您的代码会同时具有时间和空间位置。当您的代码读取some_array[0]
时,如果在缓存中找不到其地址,则从主存储器读取该地址,并将包含它的整个块复制到缓存中。它取代了某个策略后的其他块:例如MRU。
然后,当您稍后访问some_array[1]
时,其块已经在缓存中,因此读取时间将更短。请注意,您在很短的时间内访问了同一个块。所以你有空间和时间的地方。
缓存内存利用空间和时间局部性来提供更快的内存访问。另一方面,您的代码是否可以利用这一点完全是一个完全不同的问题。然而,编译器将为您完成大部分优化,因此您只应在查找配置文件会话中的瓶颈后关注此问题。在Linux环境中,Cachegrind非常适用于此。
答案 2 :(得分:2)
此代码在指令缓存中具有时间局部性,因为您在每个循环中重复代码(假设您的优化器没有展开循环)。它在数据缓存中也有空间局部性,因为如果你访问数组元素i,你很快就会访问元素i + 1,i + 2等。如果你的数据缓存行大小是16字节而你的数组是32位整数,那么当您要求元素0时(假设我们的数组在缓存行边界处开始),您的数据缓存还会加载元素1,2和3。
答案 3 :(得分:1)
代码只有空间局部性但没有时间局部性 - 在高速缓存存储器访问的上下文中。
在将数据加载到缓存中时,会加载整个行/块 - 因此后续访问完全相同的内存位置以及也是缓存中同一块的一部分的地址将具有快速访问时间。
有一些方法可以优化代码,以便从缓存中获取大量读取,而不是直接从主内存中读取: 1.如果您可以通过利用第一个缓存未命中来访问所有附近的内存地址,并且在此块被逐出缓存之前 - 那么您可以利用空间局部性。 2.如果在高速缓存中的块被逐出之前,您的程序需要访问相同的内存位置,那么您将利用时间局部性。
像矩阵乘法这样的例子会同时具有时间和空间位置。