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

线程缓存使用、多核代码性能及缓存术语相关技术咨询

代码多核扩展性差的原因及相关疑问解答

相关代码

#include <stdlib.h>
#include <stdio.h>
#include <omp.h>
int main(int argc, char *argv[]) {

 long long int tosses = atoll(argv[1]);
 long long int hits = 0;
 int threads = atoi(argv[2]);
 double start, end;
 int i;
 unsigned int seeds[threads];
 for (i = 0; i < threads; i++)
 seeds[i] = i + 1;
 start = omp_get_wtime();
 #pragma omp parallel reduction(+:hits) num_threads(threads)
 
 {
     int myrank = omp_get_thread_num();
     long long int local_hits = 0, toss;
     double x, y;
     #pragma omp for
     for (toss = 0; toss < tosses; toss++) {
     x = rand_r(&seeds[myrank])/(double)RAND_MAX * 2 - 1;
     y = rand_r(&seeds[myrank])/(double)RAND_MAX * 2 - 1;
     if (x*x + y*y < 1)
     local_hits++;

 }

     hits += local_hits;

 }

     end = omp_get_wtime();
     printf("Pi: %f\n", 4.0 * hits / tosses);
     printf("Duration: %f\n", end-start);
     return 0;
}

原问题:为何这段代码在多核环境下扩展性极差?

这段代码扩展性差的核心原因是伪共享(False Sharing):
代码中所有线程的种子存储在数组seeds中,每个种子是4字节的整型,而系统cache line为64字节,意味着单个cache line会容纳16个连续的种子。当多个线程同时修改各自的种子时,哪怕只修改其中一个,整个cache line会被标记为失效,其他共享同一cache line的线程需要重新从主存加载该cache line,频繁的缓存失效和主存访问会大幅拖慢性能,导致多核扩展时性能不升反降甚至变差。


具体疑问解答

1. 上述表述想传达什么?第17/33个核心的cache line同样可能失效,这与1-16核心有何不同?

先看你提到的这段表述:

当核心数超过16或32时,性能会有小幅提升。种子为整型值,占4字节内存。本系统的cache line为64字节,因此单个cache line可容纳16个种子。当线程数增至17/33时,新增种子会单独占用一个cache line,避免线程进一步受阻。

这段表述讲的是伪共享的部分缓解逻辑:

  • 当线程数在1-16时,所有线程的种子都挤在1个或多个满的cache line里(比如16个种子占1行,32个占2行),每个线程修改自己的种子都会导致所在cache line失效,同一行里的其他线程都要重新加载,伪共享冲突非常频繁。
  • 当线程数增至17或33时,新增的第17/33个种子会单独占用一个新的cache line(因为前16/32个已经占满了整数行),这个线程修改自己的种子时,只会让自己的cache line失效,不会影响其他线程的cache line,避免了更严重的伪共享冲突,因此性能会有小幅提升。
    简单说,1-16线程是“多个线程抢用同一cache line”,17+线程里新增的线程是“独占cache line”,冲突范围缩小了。

2. 线程的独立内存(栈内存/私有内存)属于cache memory还是主内存?

线程的栈内存、私有内存本质上是主内存的一部分,只是CPU会把频繁访问的私有内存数据加载到cache memory中做高速缓存。cache是主存的一层高速缓冲,不是独立的内存空间,私有内存的物理存储在主存,但会被缓存到cache以提升访问速度。

3. 如何在cache memory层面关联cache line与block?

  • cache line是CPU cache的最小数据操作单位(这里是64字节),**block(内存块)**是主存中与cache line对应的等量数据块。
  • 当CPU需要访问主存中的某块数据时,会把整个block(大小等于cache line)加载到cache的一个空闲cache line中。后续对该block内数据的访问,都会直接操作cache line中的缓存数据,直到该cache line失效被替换。简单来说,cache line和主存block是一一对应的映射关系,大小完全相同,cache line是block在cache中的缓存副本。

内容的提问来源于stack exchange,提问作者Jeet

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 02:10:19