54 | 理解Disruptor(上):带你体会CPU高速缓存的风驰电掣
54 | 理解Disruptor(上):带你体会CPU高速缓存的风驰电掣
讲述:徐文浩
时长08:49大小8.09M
Padding Cache Line,体验高速缓存的威力
使用 RingBuffer,利用缓存和分支预测
总结延伸
推荐阅读
课后思考
赞 23
提建议
精选留言(21)
- 小海海2019-09-09老师,有个疑惑的地方:文中讲了RingBuffer类利用缓存行填充来解决INITIAL_CURSOR_VALUE伪共享的问题,但是我记得Java对象内存布局是:实例变量放在堆区,静态变量属于类,放在方法区,而堆区和方法区在内存里肯定是隔离开的,但是RingBuffer的前后填充字段都是实例字段,而INITIAL_CURSOR_VALUE是静态常量,所以实际运行中他们肯定不是紧密排列在一起的,那么就解决不了伪共享的问题了,况且RingBuffer的子类RingBufferFields还有其他实例字段,如:indexMask、entries、bufferSize、sequencer,这些字段都是final修饰的,即对象构建后不会再修改,所以我理解前后的缓存行填充守护的应该是这几个字段,而且从子类RingBufferFields的命名也可以看出前面那几个字段才是想要缓存的字段。希望得到老师的回复,另外课程快结束了,一路跟下来收获很大,我准备这段时间二刷来巩固下^_^展开
作者回复: 我回头重新看了一下代码,我觉得你说的是对的,Padding对应的是RingBufferFields里面的字段,而不应该是INITIAL_CURSOR_VALUE,我去订正一下。
共 4 条评论44 - 山间竹2020-01-06在java8中,jvm团队搞出了@Contended注解来进行支持,在你需要避免“false sharing”的字段上标记注解,这可以暗示虚拟机“这个字段可以分离到不同的cache line中”,这是JEP 142的目标。
作者回复: 👍
38 - D2019-09-06这个是不是和前面讲的msei有一定关系啊,请徐老师点拨
作者回复: 没错,看来你读的时候很仔细地思考过。 当我们的对于数据修改,修改了cache之后,这个数据如果要同步到主内存,那么就会需要通过MSEI协议来在各个CPU Core的Cache里面保持数据同步。 那么是否需要同步主内存,会引发另外一个知识点,就是Memory Barrier/Fence,这部分知识点其实还可以单独拿来说两讲。你可以先去搜索上面的关键词,了解一下。
共 2 条评论22 - -_-|||2020-01-31“而 Disruptor 很取巧地在需要频繁高速访问的变量,也就是 RingBufferFields 里面的 indexMask 这些字段前后,各定义了 7 个没有任何作用和读写请求的 long 类型的变量。”为什么前后各7个,cache line 就没有写的请求,就是因为8个long正好64byte吗,为什么没有写的呢?
作者回复: -_-_aaa 同学, 你好,indexMask是一个第一次写入之后就不变动的变量了。你可以看到在代码里面这是一个Java的final变量。 前后7个就是因为8个long正好64byte,这样cache line无论在哪个位置被加载,这64个byte在第一次加载到cache line之后就不再需要更新了。
共 5 条评论19 - leslie2019-09-06老师今天说的这个东西其实就是MQ:只不过现在的MQ基本上是在充分利用内存/缓存,而disruptor其实是在利用CPU cache。刘超老师有一点确实没有说错“计算机组成原理和操作系统相辅相成”:学到今天去相互结合确实发现这种收益远比单独学习好。 扩展的问老师一个问题:现在所谓的智能芯片或者说前端时间提出的智能芯片,会对后续产生革命性影响么?毕竟硬件的i5到现在差不多十多年了其实进步不大,这十余年最大的变化莫过于内存容量的暴涨造就了nosql、MQ的兴起,如果说将来cache的变化是吧同样可能早就类似于老师今天所说的Disruptor这种基于CPU Cache技术的兴起。 今年华为的AI CPU、老美那边的云计算CPU似乎实验室测试已经通过了:毕竟从奔腾4之后到现在近20年了,老师今天所说的又刚好符合现在关键硬件CPU的革新时期?老师对此是如何看待?希望老师能提点。展开
作者回复: 提点谈不上,对于芯片和硬件我连从业者都还算不上。 不过过去几年的繁荣主要是来自于Intel CPU的极限性能提升已经到头了。所以反而大家回头去找其他的解决方案,在体系结构层面又有了很多新的机会。 我觉得大家都可以去读一读 David Patterson 老爷爷的 <计算机体系结构新黄金时代:历史、挑战和机遇> 这个访谈 https://www.bilibili.com/video/av46710093/
共 2 条评论16 - Scott2019-09-06最好说明一下,这种填充cache line的手法是为了防止False Sharing
作者回复: 是的,篇幅有限,所以没有太具体解释False Sharing和Memory Fence,欢迎大家留言分析这两部分知识点。
12 - 易儿易2019-09-08经典的东西总是容易被频繁引用,disruptor记得没错应该是在java并发实战专栏里被王宝令老师讲过,今天又一次学习,加深了印象……拍个双响马屁:两位老师都有很高的水准,深入浅出!
作者回复: 谢谢支持。Disruptor在2011年开源的时候其实是让很多Java开发同学们感到惊艳的,是很值得仔细研读的一份代码
5 - 等风来2019-10-10老师, 我对于前后7个long有点疑惑, 我大概知道是为了防止被换出, 但就是不知道为什么可以😂, 可以举例说明一下吗共 2 条评论3
- jssfy2021-10-28这一系列文章太赞了,这几天一有空就看,完全停不下来!真实场景代码配合原理,特别是各个文末推荐的阅读,真所谓授之以渔。2
- 余巍2020-11-06注意一下类是abstract。父子类属性原理。pad父类填充属性在前,field父类的属性被保护在中间,ringbuffer子类填充属性在最后。这样就杜绝被其他cache line影响。2
- InvisibleDes2020-10-17对分支预测的执行很有利,这一点没有看懂2
- -_-|||2020-01-31“我们现在的 64 位 Intel CPU 的计算机,缓存行通常是 64 个字节(Bytes)”,64位为什么不是64bit而是设计成64Byte的缓存行,感觉应该叫64比特intel CPU的计算机。
作者回复: -_-_aaa同学, 你好,64位是内存寻址空间,通常也是数据通路的字长(word size) 这个和缓存行之间没有对应关系。 我们也可以把缓存行设计成 16个word,也就是128 Bytes,但是并不会叫他128位计算机。
1 - 曾经瘦过2019-11-01赞,之前还以 计算机组成原理主要是架构师 选择技术 硬件 的时候使用的,原来在代码层面也可以这样使用。不过虽然能看懂他代码的意思,但是还不不太理解他是如何实现的,怎么写可以做到这样的,需要进一步的研究一下1
- 许童童2019-09-07老师讲得实在是太好了。
作者回复: 谢谢支持
1 - Geek_e9a05e2022-07-19请教一下大家,老师文中说了数组形式的数据进行遍历访问时,会增加分支预测的准确性,我不太理解,为什么呢?共 1 条评论1
- Eden Ma2022-01-10有意思
- Honer2021-10-26这个缓冲行填充让我想起了内存对齐
- 赵源😈2021-03-04一直有个问题想问老师:老师的表格中L1 cache 和L2 cache价格一样,但是L2更慢,那为什么不去掉L2 cache呢?共 1 条评论
- Paul Shan2020-09-06老师,现在只读变量使用地越来越多,为什么CPU没有提供特定的指令来优化只读变量的高速缓存(至少给开发人员一个选择,让这些变量尽量存在高速缓存而不调出)。不然也不会逼得Disruptor采用非常令人费解的填充方法,让字段常驻在缓存中。共 1 条评论
- 拓山2019-10-25这个填充思路 闻所未闻。 实在脑洞大开,赞!