什么是伪共享?

什么是伪共享?

伪共享(False Sharing)是多线程编程中的一种性能问题,它发生在多个线程同时访问不同的变量,但这些变量却共享同一缓存行(cache line)时。尽管这些变量并不相互依赖,但由于它们的存储位置在缓存中靠得很近,导致处理器频繁地无效化(invalidate)缓存行,从而影响性能。

缓存行的基本概念

在现代计算机中,CPU 使用缓存来提高内存访问速度。缓存通常分为多个层次(L1、L2、L3),每个层次的容量和访问速度各不相同。CPU 从主内存读取数据时,通常是以缓存行(通常是 64 字节)为单位进行读取的。这意味着,访问缓存行中的一个字节将导致整个缓存行被加载到 CPU 的缓存中。

伪共享的发生

伪共享通常发生在以下情况下:

  1. 多个线程:多个线程并发地访问和修改不同的变量。
  2. 相同的缓存行:这些变量位于同一个缓存行内,导致 CPU 每次更新某个变量时都要使得包含其他变量的缓存行失效。

例如,考虑以下代码:

cpp 复制代码
#include <iostream>
#include <thread>
#include <vector>
#include <chrono>

const int NUM_THREADS = 4;
const int NUM_ITERATIONS = 10000000;

struct Data {
    int a; // 变量 a
    int b; // 变量 b
    // 可能存在伪共享
};

Data data[NUM_THREADS];

void increment(int index) {
    for (int i = 0; i < NUM_ITERATIONS; ++i) {
        data[index].a++; // 线程修改 a
        data[index].b++; // 线程修改 b
    }
}

int main() {
    std::vector<std::thread> threads;
    for (int i = 0; i < NUM_THREADS; ++i) {
        threads.emplace_back(increment, i);
    }

    for (auto& t : threads) {
        t.join();
    }

    return 0;
}

在这个示例中,data 数组的每个元素都有两个整数变量 ab。假设这两个变量存储在同一个缓存行中,当多个线程同时修改 ab 时,可能会导致伪共享。这是因为每个线程在更新 a 时,可能会导致存储 b 的缓存行失效,从而引发频繁的缓存行无效化。

伪共享的影响

伪共享会导致以下几个问题:

  1. 性能下降:由于频繁的缓存行无效化,CPU 可能会花费大量时间在数据一致性上,从而影响整体性能。
  2. 增加的延迟:每次访问共享缓存行时,CPU 需要等待,从而增加了延迟。
  3. 吞吐量降低:在多线程环境中,伪共享可能导致 CPU 的利用率下降,影响吞吐量。

如何避免伪共享

避免伪共享的方法主要包括:

  1. 内存对齐 :通过确保变量在内存中对齐到缓存行边界,可以减少伪共享的发生。例如,使用 alignas 关键字来对齐结构体。

    cpp 复制代码
    struct alignas(64) Data {
        int a;
        int b;
    };
  2. 增加缓存行的使用:将变量放置在不同的缓存行中,可以有效避免伪共享。例如,在结构体中添加填充变量(padding)以确保不同变量位于不同的缓存行。

    cpp 复制代码
    struct Data {
        int a;
        char padding[60]; // 填充到 64 字节
        int b;
    };
  3. 分离数据结构:在多线程应用中,将数据分散到不同的结构体中,每个线程使用独立的结构体,避免共享数据。

  4. 使用原子操作 :在某些情况下,可以使用原子操作(如 std::atomic)来减少对共享变量的直接访问,降低伪共享的风险。

总结

伪共享是多线程编程中的一个常见性能问题,它发生在多个线程同时访问位于同一缓存行中的不同变量时。通过合理的内存对齐和数据结构设计,可以有效避免伪共享,提升多线程应用的性能。在进行高性能多线程开发时,了解伪共享及其影响至关重要。

相关推荐
SomeB1oody8 小时前
【RustyML入门】6.3. 并行归约
开发语言·后端·机器学习·rust·教程
Profile排查笔记9 小时前
指纹浏览器哪个好?从 Profile、代理、权限和自动化能力判断是否适合
前端·人工智能·后端·自动化
用户938515635079 小时前
用 AI 结对编程从 0 搭一个"单词后台管理系统":Next.js + Supabase + Drizzle + shadcn/ui 全记录
后端·postgresql·next.js
爱学习的小邓同学9 小时前
Golang --- (1)第一个Golang程序
开发语言·后端·golang
小灰灰搞电子11 小时前
Rust+Slint 实现的“DNA双螺旋”加载动画源码分享
后端·rust·slint·加载动画
面向Google编程11 小时前
向量库不再囤数据:Milvus 3.0 零拷贝直读数据湖
后端
IT_陈寒12 小时前
Redis内存警告竟是因为这个不起眼的配置项
前端·人工智能·后端
Python私教12 小时前
AI 漫剧角色一进分镜就变脸?把提示词升级成“角色 ID + 镜头合同”
后端
Python私教12 小时前
一次生成 20 个角色却全都撞脸:我用“角色合同”重做了批量生成流程
后端
用户5944041035613 小时前
Go 语言高性能 Web 服务开发:基于 Gin + GORM + Redis 构建 RESTful API
后端