JUC并发编程与高性能内存队列disruptor实战-下 (4)

Disruptor是LMAX公司LMAX Development Team开源的高性能内存队列,是一个高性能线程间消息传递库,提供并发环缓冲数据结构的库;它的设计目的是在异步事件处理体系结构中提供低延迟、高吞吐量的工作队列。它能够让开发人员只需写单线程代码,就能够获得非常强悍的性能表现,同时避免了写并发编程的难度和坑; 其本质思想在于多线程未必比单线程跑的快。

缓存行

CPU 为了更快的执行代码,当从内存中读取数据时并不是只读自己想要的部分, 而是读取足够的字节来填入高速缓存行。根据不同的 CPU ,高速缓存行大小不同,有32个字节和64个字节处。这样,当CPU访问相邻的数据时,就不必每次都从内存中读取,提高了速度,这是因为访问内存要比访问高速缓存用的时间多得多。这个缓存是CPU内部自己的缓存,内部的缓存单位是行,叫做缓存行。

当CPU尝试访问某个变量时,会先在L1 Cache中查找,如果命中缓存则直接使用;如果没有找到,就去下一级,一直到内存,随后将该变量所在的一个Cache行大小的区域复制到Cache中。查找的路线越长,速度也越慢,因此频繁访问的数据应当保持在L1Cache中。另外,一个变量的大小往往小于一个Cache行的大小,这时就有可能把多个变量放到一个Cache行中。下面代码举例数组命中缓存行和随机读写执行耗时差异:

package cn.itxs.disruptor; public class CacheMain { private static final int ARR_SIZE = 20000; public static void main(String[] args) { int[][] arrInt = new int[ARR_SIZE][ARR_SIZE]; long startTime = System.currentTimeMillis(); // 第一种情况为顺序访问,一次访问后,后面的多次访问都可以命中缓存 for (int i = 0; i < ARR_SIZE; i++) { for (int j = 0; j < ARR_SIZE; j++) { arrInt[i][j] = i * j; } } long endTime = System.currentTimeMillis(); System.out.println("顺序访问耗时" + (endTime - startTime) + "毫秒"); startTime = System.currentTimeMillis(); // 第二情况为随机访问,每次都无法命中缓存行 for (int i = 0; i < ARR_SIZE; i++) { for (int j = 0; j < ARR_SIZE; j++) { arrInt[j][i] = i * j; } } endTime = System.currentTimeMillis(); System.out.println("随机访问耗时" + (endTime - startTime) + "毫秒"); } }

image-20220117160149641

伪共享

当CPU执行完后还需要将数据回写到主内存上以便于其它线程可以从主内存中获取最新的数据。假设两个线程都加载了相同的CacheLine即缓存行数据

数据 A、B、C 被加载到同一个 Cache line,假设线程 1 在 core1 中修改 A,线程 2 在 core2 中修改 B。

线程 1 首先对 A 进行修改,这时 core1 会告知其它 CPU 核,当前引用同一地址的 Cache line 已经无效,随后 core2 发起修改 B,会导致 core1 将数据回写到主内存中,core2 这时会重新从主内存中读取该 Cache line 数据。

可见,如果同一个CacheLine的内容被多个线程读取,就会产生相互竞争,频繁回写主内存,降低了性能。

image-20220117162122630

核心概念

Ring Buffer:环形缓冲区通常被认为是Disruptor的主要点。但从3.0开始Ring Buffer只负责存储和更新通过Disruptor移动的数据(事件),对于一些高级用例,它甚至可以完全被用户替换。

Sequence:Disruptor使用序列作为一种方法来识别特定组件的位置。每个消费者(事件处理器)维护一个序列,就像中断器本身一样。大多数并发代码依赖于这些Sequence值的移动,因此Sequence支持AtomicLong的许多当前特性。事实上,两者之间唯一的真正区别是,Sequence包含了额外的功能,以防止Sequence和其他值之间的错误共享。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zzjdzy.html