欢迎来到天天文库
浏览记录
ID:46656966
大小:78.00 KB
页数:5页
时间:2019-11-26
《剖析Disruptor为什么会这么快(2):神奇的缓存行填充-编程开发技术》由会员上传分享,免费在线阅读,更多相关内容在工程资料-天天文库。
1、剖析Disruptor为什么会这么快(2):神奇的缓存行填充-编程开发技术剖析Disruptor为什么会这么快(2):神奇的缓存行填充译文出处:方腾E原文出处:Trisha我们经常捉到一个短语MechanicalSympathy,这个短语也是Martin博客的标题(译注:MartinThompson),MechanicalSympathy讲的是底层硬件是如何运作的,以及与其协作而非相悖的编程方式。我在上一篇文章中提到RingBuffer后,我们收到一些关于RingBuffer中填充高速缓存行的评论和疑问。由于这个适合用漂亮的图
2、片来说明,所以我想这是下一个我该解决的问题了。__(译注:MartinThompson很喜欢用MechanicalSympathy这个短语,这个短语源于赛车驾驶,它反映了驾驶员对丁•汽车有-•种天生的感觉,所以他们对丁•如何最佳的驾御它非常有感觉。)计算机入门我喜欢在LMAX工作的原因之一是,在这里工作让我明口从大学和ALevelComputing所学的东西实际上还是有意义的。做为一个开发者你可以逃避不去了解CPU,数据结构或者大0符号?——而我用了10年的职业生涯来忘记这些东西。但是现在看來,如果你知道这些知识并应用它,你能
3、写出一些非常巧妙和非常快速的代码。因此,对在学校学过的人是种复习,对未学过的人是个简单介绍。但是请注意,这篇文章包含了大量的过度简化。CPU是你机器的心脏,最终曲它來执行所有运算和程序。主内存(RAM)是你的数据(包括代码行)存放的地方。本文将忽略硬件驱动和网络Z类的东西,因为Disruptor的目标是尽可能多的在内存中运行。CPU和主内存之间有好儿层缓存,因为即使直接访问主内存也是非常慢的。如果你正在多次对-块数据做相同的运算,那么在执行运算的吋候把它加载到离CPU很近的地方就冇意义了(比如一个循环计数一你不想每次循环都跑到
4、主内存去取这个数据來增长它吧)。越靠近CPU的缓存越快也越小。所以L1缓存很小但很快(译注:L1表示-•级缓存),并且紧靠着在使用它的CPU内核。L2大一些,也慢一些,并且仍然只能被一个单独的CPU核使用。L3在现代多核机器中更普遍,仍然更大,更慢,并且被单个插槽上的所有?CPU核共享。最后,你拥有一块主存,由全部插槽上的所有CPU核共享。当CPU执行运算的时候,它先去L1查找所需的数据,再去L2,然后是L3,最后如果这些缓存屮都没冇,所需的数据就要去主内存拿。走得越远,运算耗费的时间就越长。所以如果你在做一些很频繁的事,你要
5、确保数据在L1缓存中。Martin和Mike的?QConpresentation演讲中给出了一些缓存未命中的消耗数据:从CPU到大约需要的CPUf司期大约需要的时间主存约60-80纳秒QPI总线传输约20ns(betweensockets,notdrawn)L3cache约40-45cycles,约15nsL2cache约10cycles,约3nsLIcache约3-4cycles,约Ins寄存器1cycle如果你的目标是让端到端的延迟只冇10毫秒,而其屮花80纳秒去主存拿一些未命中数据的过程将占很重的一块。缓存行现在需要注意
6、一件冇趣的事情,数据在缓存中不是以独立的项來存储的,如不是一个单独的变量,也不是一个单独的指针。缓存是由缓存行组成的,通常是64字节(译注:这篇文章发表时常用处理器的缓存行是64字节的,比较旧的处理器缓存行是32字节),并口它有效地引用主内存中的一块地址。一个Java的long类型是8字节,因此在一个缓存行屮可以存8个long类型的变量。(为了简化,我将忽略多级缓存)非常奇妙的是如果你访问一个long数组,当数组小的一个值被加载到缓存小,它会额外加载另外7个。因此你能非常快地遍历这个数组。事实上,你可以菲常快速的遍丿力在连续的
7、内存块中分配的任意数据结构。我在第一篇关于ringbuffer的文章中顺便提到过这个,它解释了我们的ringbuffer使用数组的原因。因此如果你数据结构中的项在内存中不是彼此相邻的(链表,我正在关注你呢),你将得不到免费缓存加载所带来的优势。并且在这些数据结构屮的每一个项都可能会出现缓存未命中。不过,所有这种免费加载有一个弊端。设想你的long类型的数据不是数组的一部分。设想它只是一个单独的变量。让我们称它为head,这么称呼它其实没有什么原因。然后再设想在你的类中有另一个变量紧挨着它。让我们直接称它为ta订。现在,当你加载
8、head到缓存的时候,你也免费加载了tail。听想来不错。直到你意识到ta订正在被你的生产者写入,而head正在被你的消费者写入。这两个变量实际上并不是密切相关的,而事实上却要被两个不同内核中运行的线程所使用。设想你的消费者更新了hCBd的值。缓存中的值和内存中的值都被更新了
此文档下载收益归作者所有