问答题1012/1053“伪共享”出现的原因是什么?

难度:
2021-11-02 创建

参考答案:

伪共享(False Sharing)是指在多线程环境中,多个线程并发访问不同的变量,这些变量被缓存到同一个缓存行中,导致性能下降。尽管这些线程访问的是不同的变量,但由于它们位于同一个缓存行内,它们之间的访问会相互影响,产生不必要的缓存同步,从而影响程序性能。

伪共享的原因

伪共享的出现主要是由于以下几个原因:

  1. CPU缓存行的存在

    • 现代CPU有多个层次的缓存(如L1、L2、L3缓存),这些缓存是为了加速数据访问。CPU缓存通常以缓存行(Cache Line)为单位来存储数据。
    • 通常,缓存行的大小是64字节,意味着一个缓存行可以存储64字节的数据。
  2. 变量存储在相同的缓存行

    • 当多个线程访问不同的变量时,如果这些变量恰好被存储在同一个缓存行中,那么它们就会发生伪共享。
    • 即使不同线程访问的是不同的变量,CPU也会把整个缓存行加载到缓存中。当一个线程修改缓存行中的某个变量时,其他线程也会受到影响,即使它们访问的是缓存行中的其他变量,因为整个缓存行会被标记为失效,从而导致频繁的缓存一致性操作(如缓存同步、无效化)。
  3. 缓存一致性协议

    • 为了确保不同CPU核心之间的数据一致性,CPU会使用缓存一致性协议(如MESI协议)。当一个线程修改了缓存行中的数据,其他线程会被通知缓存行已经发生变化,导致缓存失效和同步。
    • 如果多个线程访问同一个缓存行中的不同变量,频繁的缓存失效和同步会导致性能下降,这就是伪共享的本质。

伪共享的表现

伪共享会导致以下问题:

  • 性能下降:当多个线程频繁修改和读取存储在同一个缓存行中的数据时,会导致缓存行频繁地被失效和同步,增加了缓存一致性操作的开销,从而降低了程序的整体性能。
  • CPU缓存争用:尽管访问的是不同的数据,但由于这些数据在同一个缓存行中,多个线程在并发访问时会导致缓存争用。

如何避免伪共享

为了避免伪共享,可以采取以下几种方法:

  1. 缓存行对齐

    • 使用适当的方式将共享变量对齐到不同的缓存行。可以通过 @sun.misc.Contended 注解或使用 @NoUnroll 注解来强制将数据放置到不同的缓存行中。
    • 在一些场景下,可以通过手动填充“填充字节”或调整数据结构来避免多个变量位于同一缓存行。
  2. Padding技术

    • 通过在共享变量之间插入“填充”变量来确保不同的变量位于不同的缓存行中。这种方式通过使用多余的内存来避免变量之间共享缓存行,降低缓存一致性协议带来的性能开销。

    例如,如果一个变量占用64字节的缓存行,则可以在变量之间插入一些无用的空字段,以确保变量不被放置在同一个缓存行中。

  3. 设计数据结构

    • 将经常一起访问的数据放在一起,而将不常访问的数据放在不同的缓存行中。这种设计能够最大限度地避免伪共享的发生。

最近更新时间:2024-12-09