跟我学c++中级篇——C++中的缓存利用

news/2024/12/24 0:00:28 标签: c++, 缓存

一、缓存

学习过计算机知识的一般都知道缓存这个概念,大约也知道缓存是什么。但是如果是程序员,如何更好的利用缓存,可能就有很多人不太清楚了。其实缓存的目的非常简单,就是了更高效的操作数据。大家都听说过“局部性原理”,可以这样说,如果计算机中不存在局部性原理这个概念,就不大会有缓存这个概念。
局部性原理可以划分为时间局部性和空间局部性,这个非常好理解。前者指在较短的时间内不断的访问相同的数据;后者则为访问的数据空间范围较小(比如数组,可能更容易访问附近的数据)。
这里不给大家分析硬件或者其它什么几级缓存的相关技术,那些分析无论是书籍还是资料或者网上都非常多,这里只分析缓存的应用级别的情况。
伪共享 局部性原理

二、缓存命中

一般来说,缓存的主要作用就是增加了一个快速访问的中间层,减少了去较慢的内存中操作数据的过程。所以其命中率可以考虑下面两个方面:
1、缓存大小
缓存的大小直接决定的命中率的高低,理论上讲,缓存越大越好。但这玩意儿贵啊。而且一般缓存都在CPU内部,成本相当高昂。所以要大小适中,后来为了增加命中率,又非常聪明的想出了多级缓存的方式,从而平衡命中率和命中代价。至于缓存分级有兴趣可以查看一下相关书籍。
2、缓存替换策略
缓存也可以看做内存,所以它也有管理的策略。想一下内存中如何替换内存页,缓存基本也差不多。这里就存在一个问题,如果当几次没有命中的数据如何被替换?假如刚刚替换出去的又要访问,不就降低了访问的效率么。所以这个替换的策略也非常重要,常见的如LRU,FIFO,LFU等等,大家可查看相关的资料,这里不是重点就不展开了。
一般来说,只要指定是硬件,缓存基本大小就无法更改了。相关的替换策略一般也很少改动,但可以根据需要选取合适的CPU更好。

三、C++如何更高效的利用缓存

既然控制不了缓存的大小,但可以根据相关的策略和缓存的原理进行编码的控制。缓存的原理就是局部性的问题,也即空间和时间上的局部性。那么在时间局部性上就可以把经常访问的数据放到缓存(或寄存器);而空间局部性上就可以把经常访问的相关数据放在一起引入缓存中去。那大方向就指明了,C++编码可以做如下的控制:
1、内存处理
要想将内存的数据有效的转化为缓存,提高命中效率,可以从优化布局,比如常见的结构体的字段的顺序啊,指针数据的处理啊等等。内存对齐 ,这个更常见。把相关的数据搞到和Cache行大小相关(最小单元的处理);另外就是多使用类似数组的连续内存数据结构,少使用类似List这种非连续的内存。
2、函数处理
要想增加函数处理的效率,首先想到的就是使用内联函数,同时减少函数中的对象的传递,特别是大对象的传递。要避免过深的嵌套调用和递归调用,防止缓存中途失效,还需要重新从内存加载就得不偿失了。
3、循环处理
前面分析过循环处理的很多优化,往往编译器都能做到。但还是需要注意要对相关的循环过程中的循环次数的优化,特别是在处理一些大型的数据时(比如特别大的数组、矩阵等)可以考虑前面并行编程优化时提到的分块处理,分治同样也适应缓存的优化。
4、IO的控制
在一些库或接口中,提供了硬盘等IO的缓冲设置,其实这也可以划到缓存当中来。如果使用良好的预读写函数处理,可能大幅度提高缓存的命中率真,从而提高读写的效率。
5、使用内存或对象池
这个很容易明白,其实和使用数组方式类似,将相关的对象直接固定在一个位置而不是反复的分配,无法形成有效的缓存
6、减少判断和跳转的语句
这个不光对缓存有用,对CPU中的流水指令也很重要,经常的反复的无规则的跳转,缓存就失去了意义 。
7、减少内存碎片
内存碎片增多,就意味着连续性的降低,从而导致缓存在固定的大小范围内引入的相关范围的减少,从概率上讲,会降低命中率。消除内存碎片最常用的是使用内存池技术。
8、消除伪共享
这个非常重要,在如今多核泛滥的情况下,不处理这种情况,就等于是降低命中率。可以参看前面的文章“多线程的伪共享”中消除的方法即使用填充法或使用一些关键字来处理。
9、处理好并行情况的竞态
这个其实和判断语句有些相似,都是尽量保证高命率的可能的内存数据保留在缓存中,毕竟缓存的大小有限。

四、例程

下面看一些简单的应用:

//使用关键字处理对齐
struct alignas(8) Test {
    int a;
    int32_t b;
};
//数组行优先访问
for (int r = 0; r < 1000; ++r) {
    for (int c = 0; c < 1000; ++c) {
        array[r][c] = 0;
    }
 }
}
//循环优化
for (int i = 0; i < 800; i += 8) {
    readData(array[i]);
    readData(array[i+1]);
    readData(array[i+2]);
    readData(array[i+3]);
    readData(array[i+4]);
    readData(array[i+5]);
    readData(array[i+6]);
    readData(array[i+7]);
}
//经常访问数据放置相近
struct Data{
...
int height,weight,old;

...
};

其实这些方法很简单,就是使用的时候要在思想上有一个处理的想法,而不是粗暴的想到哪儿就写到哪儿。

五、总结

总之,如何在编程层面对缓存命中进行处理,是一个综合考量的过程。开发者需要根据实际情况如何用最小的代价实现更好的命中率。不过可惜的是,对于大多数程序员来说,这都是在实际场景中很难遇到的情况。对于普通程序员来说,好好优化,但不要过度优化代码,更不要过早的展开优化。养成一个好的数据定义的内存布局概念,就基本可以达到要求了。
不过,需要注意的是,不同的架构芯片可能缓存机制有所不同,如果真要写贴近硬件的缓存机制相关代码,需要严格的按照相关的硬件说明进行。


http://www.niftyadmin.cn/n/5797135.html

相关文章

Chapter 3-1. Detecting Congestion in Fibre Channel Fabrics

Chapter 3. Detecting Congestion in Fibre Channel Fabrics This chapter covers the following topics: 本章包括以下主题: Congestion detection workflow. Congestion detection metrics. Congestion detection metrics and commands on Cisco MDS switches. Automatic A…

开源轮子 - EasyExcel01(核心api)

EasyExcel01 - 核心api 本文整理自掘金大佬 - 竹子爱熊猫 https://juejin.cn/post/7405158045662576640 文章目录 EasyExcel01 - 核心api一&#xff1a;初相识EasyExcel1&#xff1a;写入excel入门2&#xff1a;读取Excel入门 二&#xff1a;数据模型注解1&#xff1a;读写通用…

centos单机部署seata

文章目录 场景分析下载seata包启动 场景 centos7.9 jdk17 安装部署seata 分析 jdk和seata的版本对应关系如图 JDK版本 推荐 Seata 版本 理由 JDK 8 任何 Seata 版本 JDK 8 是 Seata 长期支持的版本&#xff0c;兼容性最好。 JDK 11 Seata 1.2.0 适合需要长期支持且性能较高的应…

Vue|scoped样式

在 Vue.js 中&#xff0c;scoped 是一个非常有用的特性&#xff0c;允许你将样式限制在当前组件的作用域内&#xff0c;避免样式泄漏到其他组件。它是通过 Vue 的单文件组件&#xff08;.vue 文件&#xff09;中的 <style> 标签实现的。 目录 案例演示创建多个vue文件如何…

opencv 项目--图像匹配

本文按照如下设计 ImageStitching_ExcessThree.py from Stitcher import Stitcher import cv2 import my_utils # 只拼接两张图片# 读取需要拼接的图片 # imageA_original cv2.imread("left_01.png") # imageB_original cv2.imread("right_01.png") ima…

深入浅出:多功能 Copilot 智能助手如何借助 LLM 实现精准意图识别

阅读原文 1. Copilot中的意图识别 如果要搭建一个 Copilot 智能助手&#xff0c;比如支持 知识问答、数据分析、智能托管、AIGC 等众多场景或能力&#xff0c;那么最核心的就是基于LLM进行意图识别分发能力&#xff0c;意图识别的准确率直接决定了 Copilot 智能助手的能力上限…

速通Python 第三节

一、顺序语句 默认情况下 , Python 的代码执行顺序是按照从上到下的顺序 , 依次执行 print("1") print("2") print("3") 执行结果一定为 "123", 而不会出现 "321" 或者 "132" 等 . 这种按照顺序执行的代码…

情报信息收集能力

红队专题-Web渗透之资产思路框架知识整理 钓鱼社工 钓鱼自动化zip域名ARP欺骗快捷方式ToolsburpsuiteApp 抓包ffuf模糊测试QingScanWiresharkCloudCFEn-Decodeffffffff0xInfodirbdirmapdirsearchdnsenum使用测试常规使用使用字典文件进行dns查询子域名暴力查询部分C类IP地址IP块…