2013-10-16 77 views
8

我剛剛發現這個庫,可提供無鎖環,即工作方式速度更快,然後渠道:https://github.com/textnode/gringo(和它的作品真的快尤其是GOMAXPROCS> 1)爲什麼結構與填充字段工作更快

但有趣的部分是用於管理隊列狀態的結構:

type Gringo struct { 
    padding1 [8]uint64 
    lastCommittedIndex uint64 
    padding2 [8]uint64 
    nextFreeIndex uint64 
    padding3 [8]uint64 
    readerIndex uint64 
    padding4 [8]uint64 
    contents [queueSize]Payload 
    padding5 [8]uint64 
} 

如果刪除 「paddingX [8] UINT64」 字段它工作慢約20%。它是如何的?

也很感謝,如果有人解釋爲什麼這種無鎖算法快得多渠道,甚至緩衝?

回答

11

填充消除了false sharing,將每個結構放在它自己的緩存行上。如果兩個變量共享一個緩存行,如果存在對另一個變量的中間寫入,則讀取未修改的變量將與讀取已修改的變量一樣昂貴。

當在多個核心上讀取變量而未修改變量時,核心將共享緩存行。這使得讀取非常便宜。在任何內核可以寫入該緩存行的任何部分之前,它必須使其他內核上的緩存行無效。如果任何核心稍後從該緩存行中讀取,則會發現緩存行失效並且必須返回到共享緩存行。當一個變量經常被修改而另一個經常被讀取時,這會造成痛苦的額外緩存一致性流量。

+0

謝謝,我不知道! – Intermernet

+0

謝謝!這是非常有趣的功能! –

3

它工作得更快,因爲它不需要鎖。 This是Java中的一個實現(稱爲Disruptor),它工作得很好,似乎是gringo的靈感。他們解釋了鎖的成本以及如何提高吞吐量here

至於填充,本文還暗示了一些原因。基本上:處理器緩存。 This paper解釋得很好。通過讓處理器訪問其1級緩存,而不是儘可能經過內存或外部緩存,您可以獲得巨大的性能提升。但是這需要採取額外的預防措施,因爲處理器將完全加載其緩存,並在每次需要時重新加載(從內存或2-3級緩存)。 在併發數據結構的情況下,正如@David Schwartz所說的那樣,虛假共享會迫使處理器更頻繁地重新加載其緩存,因爲有些數據可能會加載到內存行的其餘部分,並被修改,並強制整個緩存再次被加載。

+0

是的,我想'通過記憶一路'有點誤導。我編輯了答案。感謝您的精確! – val

+0

感謝指向Disturptor模式,真棒閱讀! –