You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

写入输出数组独立元素是否存在伪共享?CSR矩阵求和代码伪共享咨询

关于伪共享的问题解答

1. 写入输出数组的独立元素时是否存在伪共享?

会存在伪共享。

伪共享的核心原因是CPU缓存以缓存行(通常为64字节,x86架构)为最小读写单位。当不同线程写入的数组元素落在同一个缓存行内时,即使这些元素是独立的,CPU缓存一致性协议(如MESI)会要求缓存行在不同核心间同步,导致频繁的缓存失效、刷新操作,从而产生性能损耗,这就是伪共享。

比如float类型占4字节,一个64字节缓存行可容纳16个float元素。若线程0写入sum[0]、线程1写入sum[1],二者处于同一缓存行,就会触发伪共享。

2. CSR矩阵行求和代码中sum[]的伪共享问题及解决方法

是否存在伪共享?

存在伪共享。

这段代码中,每个线程负责一个行索引i,最终写入sum[i]。当线程数较多、N较大时,不同线程写入的sum[i]很大概率落在同一缓存行内,触发伪共享,导致缓存同步开销。

另外注意:原代码存在语法错误,外层for循环缺少包裹代码块的大括号,修正后的代码如下:

#pragma omp parallel for  
for (int i = 0; i < N; i++) {
    float row_sum = 0.;
    for (int k = rowOffsets[i]; k < rowOffsets[i+1]; k++){
      row_sum += values[k]; 
    }
    sum[i] = row_sum;
}

无法重新定义sum[]时的伪共享规避方案

在不能修改sum[]结构的前提下,可通过以下方法规避伪共享:

  • 调整线程调度策略,使用分块静态调度
    利用OpenMP的schedule(static, chunk_size)指定分块大小,让每个线程处理连续的、刚好填满若干缓存行的数组元素。比如针对float类型,设置chunk_size=16(对应64字节缓存行),这样每个线程写入的sum元素集中在连续的缓存行内,同一缓存行只会被一个线程操作,避免跨线程的缓存冲突。示例:

    #pragma omp parallel for schedule(static, 16)
    for (int i = 0; i < N; i++) {
        float row_sum = 0.;
        for (int k = rowOffsets[i]; k < rowOffsets[i+1]; k++){
          row_sum += values[k]; 
        }
        sum[i] = row_sum;
    }
    
  • 使用线程本地临时缓冲区,批量写入sum[]
    每个线程先将计算出的行和存储在自己的本地缓冲区中,待处理完所有负责的行后,再一次性将本地缓冲区的数据拷贝到sum[]。这样每个线程在写入sum[]时操作的是连续的内存区域,同一缓存行仅被单个线程访问,消除伪共享。示例:

    #pragma omp parallel
    {
        int tid = omp_get_thread_num();
        int num_threads = omp_get_num_threads();
        int start = tid * (N / num_threads);
        int end = (tid == num_threads - 1) ? N : (tid + 1) * (N / num_threads);
    
        // 线程本地临时存储,避免实时写入sum的冲突
        std::vector<float> local_sums(end - start, 0.0f);
    
        for (int i = start; i < end; i++) {
            float row_sum = 0.f;
            for (int k = rowOffsets[i]; k < rowOffsets[i+1]; k++) {
                row_sum += values[k];
            }
            local_sums[i - start] = row_sum;
        }
    
        // 批量写入sum,此时每个线程操作连续的缓存行,无跨线程冲突
        std::copy(local_sums.begin(), local_sums.end(), sum + start);
    }
    

内容的提问来源于stack exchange,提问作者Rajesh Shashi Kumar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 12:25:22