• intel false sharing 伪共享


    介绍

    在cpu设计中,有各种缓存,目前常见的是cache1 2 3(缓存1 缓存2 缓存3)三层,cache1更靠近cpu,空间更小,速度更快。cache1->cache2->cache3->内存 依次距离cpu更远,空间更大,速度更慢。缓存一般设计是由缓存行实现,每行64字节。也就是每个缓存中包含很多缓存行,每个缓存行64字节(看做一个整体)。cpu从内存把数据加载进缓存时,就是按照连续的64字节加载的,因为cpu认为如果内存中的一个数据被使用,相邻的其他数据在最近的时间段内被使用的概率更大,所以全部加载进来。

    如果数据没有修改,那么下次再访问就可以命中,直接从缓存获取数据,而不用到内存中去。如果数据被修改,那么相关联的一个缓存行64字节数据都会失效,下次读取数据要重新从内存获取。

    这里就有一个问题,a和b变量相邻,如果a和b都频繁修改,或者其中一个频繁修改,那么必然会影响到另一个。因为缓存是按照缓存行(64字节)作为最小处理单位,如果a修改,a相关联的缓存行(包含b的数据)都会失效,下次读取b(虽然b没有修改)也无法命中,必须从内存获取,这就叫做伪共享。

    这实际上是一个正常的现象,一般不用考虑,但是有些特殊情况,需要进行调优。如何避免这种问题?可以在a和b中间增加64字节的数据,把a和b强行分到两个cache line(如果a和b是在同一个结构体或者类似于数组相邻)。

    这个技巧有什么用呢,就是如果你有一个结构体,在代码中需要频繁的使用,定义了这个结构体的数组等类似的情况,那么可以使用__attribute__((aligned(64)));让结构体按照64字节对齐。这个是gcc的参数,意思是如果结构体最大变量不足64字节,就按照64字节对齐;如果大于64字节,则按照对应的长度对齐。

    示例

    #include <stdio.h>
    #include <pthread.h>
    #include <unistd.h>
    #include <time.h>
    
    struct MyStruct
    {
        long a;
        char c[64];
        long b;
    }__attribute__((aligned(64)));//这里去掉会大大影响性能
    
    void *threadf(void * arg)
    {
        struct MyStruct * a = (struct MyStruct*)arg;
        for(int i = 0; i < 100000000; i++)
        {
            a->b++;
        }
    }
    void *threadf1(void * arg)
    {
        struct MyStruct * a = (struct MyStruct*)arg;
        for(int i = 0; i < 100000000; i++)
        {
            a->a++;
        }
    }
    
    int main()
    {
        printf("size[%d]\n", sizeof(struct MyStruct));
        clock_t begin, end;
    
        begin = clock();
        pthread_t t1, t2;
        struct MyStruct ms[2];
        int res = pthread_create(&t1, NULL, threadf, &ms[0]);
        if(res != 0)
        {
            printf("err\n");
        }
        res = pthread_create(&t2, NULL, threadf1, &ms[1]);
        if(res != 0)
        {
            printf("err\n");
        }
        pthread_join(t1, NULL);
        pthread_join(t2, NULL);
        end = clock();
        double seconds  =(double)(end - begin)/CLOCKS_PER_SEC;
        printf("Use time is: %.8f\n", seconds);
        return 0;
    }
    

    gcc编译增加-lpthread链接库

  • 相关阅读:
    MondoDB 之 使用python对MongoDB排序 MondoDB -9
    MondoDB 之 使用python对MongoDB进行文档修改 MondoDB -8
    MondoDB 之 使用python对MongoDB进行查询文档 MondoDB -7
    MondoDB 之 使用python对MongoDB进行插入文档 MondoDB -6
    MondoDB 之 使用python操作MongoDB MondoDB -5
    MondoDB 之 $关键字 及 $修改器 $set $inc $push $pull $pop MondoDB -4
    MondoDB 之 数据类型 MondoDB -3
    MongoDB 之 操作增删改查 MongoDB
    简述常见数据库高可用方案
    关于MySql数据库误操作数据找回的办法
  • 原文地址:https://www.cnblogs.com/studywithallofyou/p/16695550.html
Copyright © 2020-2023  润新知