Aspire

CPU 高速缓存:原理和应用---golang

发布时间:5年前热度: 2973 ℃评论数:

package mainimport (    "fmt"    "time")func main() {    size := 20000    matrix1 := make([][]int, size)    for i := 0; i < size; i++ {        matrix1[i] = make([]int, size)    }    start1 := time.Now()    // 方法 1    for i := 0; i < size; i++ {        for j := 0; j < size; j++ {            matrix1[i][j] = i + j        }    }    fmt.Println(time.Since(start1))    matrix2 := make([][]int, size)    for i := 0; i < size; i++ {        matrix2[i] = make([]int, size)    }    // 方法 2    start2 := time.Now()    for i := 0; i < size; i++ {        for j := 0; j < size; j++ {            matrix2[j][i] = i + j        }    }    fmt.Println(time.Since(start2)) }

// 1.1769527s

// 8.5584257s


现代计算机处理器是基于一种叫对称多处理 (symmetric multiprocessing, SMP) 的概念。在一个 SMP 系统里,处理器的设计使两个或多个核心连接到一片共享内存 (也叫做主存,RAM)。另外,为了加速内存访问,处理器有着不同级别的缓存,分别是 L1、L2 和 L3。确切的体系结构可能因供应商、处理器模型等等而异。然而,目前最流行的模型是把 L1 和 L2 缓存内嵌在 CPU 核心本地,而把 L3 缓存设计成跨核心共享:

越靠近 CPU 核心的缓存,容量就越小,同时访问延迟就越低 (越快):

CacheLatencyCPU cyclesSize
L1 access~1.2 ns~4Between 32 KB and 512 KB
L2 access~3 ns~10Between 128 KB and 24 MB
L3 access~12 ns~40Between 2 MB and 32 MB

同样的,这些具体的数字因不同的处理器模型而异。不过,我们可以做一个粗略的估算:假设 CPU 访问主存需要耗费 60 ns,那么访问 L1 缓存会快上 50 倍。

在处理器的世界里,有一个很重要的概念叫访问局部性 (locality of reference),当处理器访问某个特定的内存地址时,有很大的概率会发生下面的情况:

CPU 在不久的将来会去访问相同的地址:这叫**时间局部性 (temporal locality)**原则。

CPU 会访问特定地址附近的内存地址:这叫**空间局部性 (spatial locality)**原则。

之所以会有 CPU 缓存,时间局部性是其中一个重要的原因。不过,我们到底应该怎么利用处理器的空间局部性呢?比起拷贝一个单独的内存地址到 CPU 缓存里,拷贝一个缓存行 (Cache Line)是更好的实现。一个缓存行是一个连续的内存段。

原文
https://mp.weixin.qq.com/s/viQp36FeMZSqUoFy3VrBNw


源码安装、技术讨论、二次开发等联系微信:

CPU 高速缓存:原理和应用---golang

栏目导航

  1. PHP
  2. Go
  3. Mysql
  4. Linux
  5. 前端
  6. 杂谈

手机扫码访问