我刚刚找到了一个库,它提供无锁环,比通道运行得快得多: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 8uint 64“字段,它的工作速度会慢20%。怎么可能呢?
如果有人解释为什么这种无锁算法比信道快得多,甚至是缓冲的话,我也很感激?
发布于 2013-10-16 07:44:09
填充消除了虚假共享,将每个结构放在自己的缓存线上。如果两个变量共享缓存行,则如果对另一个变量进行中间写入,则对未修改变量的读取将与读取修改后的变量一样昂贵。
当一个变量在多个核上读取而不被修改时,缓存线由内核共享。这样读起来很便宜。在任何核心可以写入该缓存行的任何部分之前,它必须使其他核心上的缓存行失效。如果任何核心稍后从该缓存行中读取,它将发现缓存行无效,必须返回共享。当一个变量经常被修改,另一个经常被读取时,这就产生了痛苦的额外缓存一致性通信量。
发布于 2013-10-16 07:50:07
它工作得更快,因为它不需要锁。这是Java中的一个实现(称为Disruptor),它工作得很好,似乎是外国佬的灵感来源。它们解释了锁的成本以及如何提高吞吐量这里。
对于填充物,本文也提出了一些原因。基本上:处理器缓存。本论文解释得很好。通过让处理器访问其级别1缓存,而不是尽可能频繁地通过内存或外部缓存,您可以获得巨大的性能提升。但这需要采取额外的预防措施,因为处理器将充分加载它的缓存,并在每次需要时重新加载它(从内存或2-3级缓存)。在并发数据结构的情况下,正如@David Schwartz所说,错误共享将迫使处理器更频繁地重新加载其缓存,因为某些数据可能被加载到内存线的其余部分,因此需要修改,并强制再次加载整个缓存。
https://stackoverflow.com/questions/19397699
复制相似问题