<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Disruptor高性能之道-局部性原理與緩沖行填充細節(jié)補充

          2022-03-02 01:43

          在之前的文章中,我們討論了Disruptor高性能實現機制中的:

          • RingBuffer環(huán)形隊列及內存預加載
          • 緩存行填充避免偽共享

          本文對之前沒有講到的細節(jié)進行補充。

          對于數組元素預加載的補充解釋

          private?void?fill(EventFactory?eventFactory){
          ??for?(int?i?=?0;?i???????entries[BUFFER_PAD?+?i]?=?eventFactory.newInstance();
          ??}
          }

          一次性填充滿整個數組,這樣做是一個比較有技巧的做法,Disruptor通過填充滿數組,在運行時改變對象的值來達到防止Java垃圾回收(GC)產生的系統(tǒng)開銷。

          換句話說就是它不需要垃圾回收。

          Disruptor是如何通過位運算提升取模效率的?

          我們已經知道,RingBufferSize為2的N次方時,可以通過位于運算提升取模效率,公式為:

          ?

          seq & (ringBufferSize - 1) == index

          ?

          即:當前event的sequence與RingBufferSize-1的差進行位于運算,就等價于sequence Mod RingBufferSize,但是效率更高。

          在Disruptor的源碼中具體是如何利用該機制的?

          ????@Override
          ????public?E?get(long?sequence)
          ????{
          ????????return?elementAt(sequence);
          ????}
          ?

          Disruptor通過get(sequence)從RingBuffer中取出下一個可用的sequence位于RingBuffer中的下標,具體實現在elementAt方法中。

          ?
          //?com.lmax.disruptor.RingBufferFields#elementAt
          protected?final?E?elementAt(long?sequence)?{
          ??return?(E)?UNSAFE.getObject(entries,?REF_ARRAY_BASE?+?((sequence?&?indexMask)?<}
          ?

          可以看到elementAt是通過UNSAFE直接調用底層方法getObject,通過遞增序列號獲取與序列號對應的數組元素。

          ?

          緩存行填充與局部性原理

          我們知道Disruptor是通過緩存行填充避免了偽共享問題。

          實際上這與 “局部性原理” 息息相關。

          ?

          解釋下什么叫做:局部性原理。

          程序的局部性原理指的是在一段時間內程序的執(zhí)行會限定在一個局部范圍內。這里的“局部性”可以從兩個方面來理解,一個是時間局部性,另一個是空間局部性。

          時間局部性指的是程序中的某條指令一旦被執(zhí)行,不久之后這條指令很可能再次被執(zhí)行;如果某條數據被訪問,不久之后這條數據很可能再次被訪問。

          而空間局部性是指某塊內存一旦被訪問,不久之后這塊內存附近的內存也很可能被訪問。

          ?

          CPU緩存讀寫就利用了局部性原理。

          當CPU從主內存加載數據A時,它會將數據A緩存至CPU的高速緩存cache中。除了A會被緩存,A附近的數據也會被緩存。

          根據局部性原理分析,由于A會被訪問,那么A周圍的其他數據也很有可能會被訪問,如果一并加載則會提升程序的性能。

          但是由于多核CPU同時修改同一緩存行,導致緩存行失效后重新加載主內存,因此出現了偽共享的問題。

          再次分析Disruptor對變量的緩存行填充原理

          首先看一下Disruptor中對 INITIAL_CURSOR_VALUE 的特殊處理。

          public?final?class?RingBuffer?extends?RingBufferFields?implements?Cursored,?EventSequencer,?EventSink
          {
          ????public?static?final?long?INITIAL_CURSOR_VALUE?=?Sequence.INITIAL_VALUE;
          ????protected?long?p1,?p2,?p3,?p4,?p5,?p6,?p7;

          RingBuffer繼承于RingBufferField

          abstract?class?RingBufferFields?extends?RingBufferPad

          RingBufferFields繼承于RingBufferPad

          abstract?class?RingBufferPad
          {
          ????protected?long?p1,?p2,?p3,?p4,?p5,?p6,?p7;
          }

          那么我們就知道,在INITIAL_CURSOR_VALUE前后各填充了7個long型變量。

          前面的 7 個來自繼承的 RingBufferPad 類,后面的 7 個則是直接定義在 RingBuffer 類里 面。

          「這14個變量沒有任何實際的用途。既不會去讀也不會去寫他們?!?/strong>

          padding.png

          可以看到,常量INITIAL_CURSOR_VALUE前后各填充了7個long型變量,無論CPU高速緩存如何加載緩存行(一個緩存行8個long型長度),整個緩存行都沒有會發(fā)生變更的數據,這個8個long類型的緩存行無論如何加載上面的內存行,都能夠讀到常量,且不會加載除了常量的其他變量。

          ?

          而INITIAL_CURSOR_VALUE是一個常量,也不會進行修改。所以一旦它被加載到CPU Cache 之后,只要被頻繁地讀取訪問,就不會再被換出 Cache 了。這也就意味著對于這個值的讀取速度,會是「一直是 CPU Cache 的訪問速度,而不是內存的訪問速度」。

          ?

          這有效地解決了偽共享的問題。


          瀏覽 84
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  www.婷婷五月天.com | 天天日天天搞 | 爱搞搞就要搞搞 | 91福利视频网站 | 人人操人人操人人操人人 |