• 首页
  • 人妻人人妻A乱人伦
  • 强伦姧人妻在线看观
  • 男朋友揉我下面很爽
  • 给学生开嫩苞的视频
  • 又粗又黄的A级裸片
  • 热点资讯

    中文字幕乱亚洲无线码淌若这两个不同中枢的线程差异修改不同的数据

    发布日期:2022-10-01 10:50    点击次数:98
    欧美在线第三页播放中文字幕乱亚洲无线码

     

    本文转载自微信公众号「小林coding」,作家小林coding 。转载本文请关系小林coding公众号。

    寰宇好,我是小林。

    周末的技术,有个读者跟我说,口试字节的技术被问到:「什么是伪分享?又该怎么幸免伪分享的问题?」

    这个其实是锻炼 CPU 缓存的问题,我之前的图解系统也有提到过。

    今天,我再跟寰宇讲一下。

    正文 CPU 如何读写数据的?

    先来意志 CPU 的架构,惟一连气儿了 CPU 的 架构,智商更好地连气儿 CPU 是如何读写数据的,关于当代 CPU 的架构图如下:

    不错看到,一个 CPU 里简单会有多个 CPU 中枢,比如上图中的 1 号和 2 号 CPU 中枢,而况每个 CPU 中枢都有我方的 L1 Cache 和 L2 Cache,而 L1 Cache 简单分为 dCache(数据缓存) 和 iCache(领导缓存),L3 Cache 则是多个中枢分享的,这即是 CPU 典型的缓存端倪。

    上头提到的都是 CPU 里面的 Cache,放眼外部的话,还会有内存和硬盘,这些存储拔擢共同组成了金字塔存储端倪。如下图所示:

    从上图也不错看到,从上往下,存储拔擢的容量会越大,而打听速率会越慢。至于每个存储拔擢的打听延时,你不错看下图的表格:

    你不错看到, CPU 打听 L1 Cache 速率比打听内存快 100 倍,这即是为什么 CPU 里会有 L1~L3 Cache 的原因,指标即是把 Cache 四肢 CPU 与内存之间的缓存层,以减少对内存的打听频率。

    CPU 从内存中读取数据到 Cache 的技术,并不是一个字节一个字节读取,而是一块一块的神志来读取数据的,这一块一块的数据被称为 CPU Line(缓存行),是以 CPU Line 是 CPU 从内存读取数据到 Cache 的单元。

    至于 CPU Line 大小,在 Linux 系统不错用底下的神志检察到,你不错看我奇迹器的 L1 Cache Line 大小是 64 字节,也就意味着 L1 Cache 一次载入数据的大小是 64 字节。

    那么对数组的加载, CPU 就会加载数组里面连气儿的多个数据到 Cache 里,因此咱们应该按照物理内存地址散播的规矩去打听元素,这么打听数组元素的技术,Cache 掷中率就会很高,于是就能减少从内存读取数据的频率, 从而可提高要领的性能。

    关联词,在咱们不使用数组,而是使用单独的变量的技术,则会有 Cache 伪分享的问题,Cache 伪分享问题上是一个性能杀手,咱们应该要遮蔽它。

    接下来,就来望望 Cache 伪分享是什么?又如何幸免这个问题?

    当今假定有一个双中枢的 CPU,这两个 CPU 中枢并走时行着两个不同的线程,它们同期从内存中读取两个不同的数据,差异是类型为 long 的变量 A 和 B, 阿立这个两个数据的地址在物理内存上是连气儿的, 在线淌若 Cahce Line 的大小是 64 字节,而况变量 A 在 Cahce Line 的开始位置,那么这两个数据是位于团结个 Cache Line 中,又因为 CPU Line 是 CPU 从内存读取数据到 Cache 的单元,是以这两个数据会被同期读入到了两个 CPU 中枢中各自 Cache 中。

    咱们来思考一个问题,淌若这两个不同中枢的线程差异修改不同的数据,比如 1 号 CPU 中枢的线程只修改了 变量 A,或 2 号 CPU 中枢的线程的线程只修改了变量 B,会发生什么呢?

    分析伪分享的问题

    当今咱们结合保证多核缓存一致的 MESI 公约,来施展这一通盘这个词的进程,淌若你还不澄莹 MESI 公约,你不错看我这篇著作「10 张图开放 CPU 缓存一致性的大门」。

    ①. 最运窜改量 A 和 B 都还不在 Cache 里面,假定 1 号中枢绑定了线程 A,2 号中枢绑定了线程 B,线程 A 只会读写变量 A,线程 B 只会读写变量 B。

    ②. 1 号中枢读取变量 A,由于 CPU 从内存读取数据到 Cache 的单元是 Cache Line,也或然变量 A 和 变量 B 的数据包摄于团结个 Cache Line,是以 A 和 B 的数据都会被加载到 Cache,并将此 Cache Line 标志为「独占」景况。

    ③. 接着,2 号中枢运转从内存里读取变量 B,通常的亦然读取 Cache Line 大小的数据到 Cache 中,此 Cache Line 中的数据也包含了变量 A 和 变量 B,老师的粉嫩小泬23p此时 1 号和 2 号中枢的 Cache Line 景况变为「分享」景况。

    ④. 1 号中枢需要修改变量 A,发现此 Cache Line 的景况是「分享」景况,是以先需要通过总线发送音讯给 2 号中枢,见告 2 号中枢把 Cache 中对应的 Cache Line 标志为「已失效」景况,然后 1 号中枢对应的 Cache Line 景况酿成「已修改」景况,而况修改变量 A。

    ⑤. 之后,2 号中枢需要修改变量 B,此时 2 号中枢的 Cache 中对应的 Cache Line 是已失效景况,另外由于 1 号中枢的 Cache 也有此疏导的数据,且景况为「已修改」景况,是以要先把 1 号中枢的 Cache 对应的 Cache Line 写回到内存,然后 2 号中枢再从内存读取 Cache Line 大小的数据到 Cache 中,临了把变量 B 修改到 2 号中枢的 Cache 中,并将景况标志为「已修改」景况。

    是以,不错发现淌若 1 号和 2 号 CPU 中枢这么继续轮流的差异修改变量 A 和 B,就会重迭 ④ 和 ⑤ 这两个要领,Cache 并莫得起到缓存的胁制,天然变量 A 和 B 之间其实并莫得任何的关系,关联词因为同期包摄于一个 Cache Line ,这个 Cache Line 中的纵情数据被修改后,都会互相影响,从而出现 ④ 和 ⑤ 这两个要领。

    因此,这种因为多个线程同期读写团结个 Cache Line 的不同变量时,而导致 CPU Cache 失效的表象称为伪分享(False Sharing)。

    幸免伪分享的格局

    因此,关于多个线程分享的热门数据,即频频会修改的数据,应该幸免这些数据刚好在团结个 Cache Line 中,不然就会出现为伪分享的问题。

    接下来,望望在本色名目中是用什么神志来幸免伪分享的问题的。

    在 Linux 内核中存在 __cacheline_aligned_in_smp 宏界说,是用于处置伪分享的问题。

    从上头的宏界说,咱们不错看到:

    淌若在多核(MP)系统里,该宏界说是 __cacheline_aligned,也即是 Cache Line 的大小; 而淌若在单核系统里,该宏界说是空的;

    因此,针对在团结个 Cache Line 中的分享的数据,淌若在多核之间竞争相比严重,为了驻扎伪分享表象的发生,不错弃取上头的宏界说使得变量在 Cache Line 里是对齐的。

    举个例子,有底下这个结构体:

    结构体里的两个成员变量 a 和 b 在物理内存地址上是连气儿的,于是它们可能会位于团结个 Cache Line 中,如下图:

    是以,为了驻扎前边提到的 Cache 伪分享问题,咱们不错使用上头先容的宏界说,将 b 的地址设立为 Cache Line 对齐地址,如下:

    这么 a 和 b 变量就不会在团结个 Cache Line 中了,如下图:

    是以,幸免 Cache 伪分享本色上是用空间换时辰的思惟,滥用一部分 Cache 空间,从而换来性能的进步。

    咱们再来看一个愚弄层面的遮蔽决策,有一个 Java 并发框架 Disruptor 使用「字节填充 + 选择」的神志,来幸免伪分享的问题。

    Disruptor 中有一个 RingBuffer 类会频频被多个线程使用,代码如下:

    你可能会合计 RingBufferPad 类里 7 个 long 类型的名字很奇怪,但事实上,它们天然看起来毫无作用,但却对性能的进步起到了至关迫切的作用。

    咱们都澄莹,CPU Cache 从内存读取数据的单元是 CPU Line,一般 64 位 CPU 的 CPU Line 的大小是 64 个字节,一个 long 类型的数据是 8 个字节,是以 CPU 一下会加载 8 个 long 类型的数据。

    笔据 JVM 对象选择关系中父类成员和子类成员,内存地址是连气儿成列布局的,因此 RingBufferPad 中的 7 个 long 类型数据四肢 Cache Line 前置填充,而 RingBuffer 中的 7 个 long 类型数据则四肢 Cache Line 后置填充,这 14 个 long 变量莫得任何本色用途,更不会对它们进行读写操作。

    另外,RingBufferFelds 里面界说的这些变量都是 final 修饰的,意味着第一次加载之后不会再修改, 又由于「前后」各填充了 7 个不会被读写的 long 类型变量,是以无论怎么加载 Cache Line,这通盘这个词 Cache Line 里都莫得会发生更新操作的数据,于是只须数据被频繁地读取打听,就天然没少见据被换出 Cache 的可能,也因此不会产生伪分享的问题。