为了账号安全,请及时绑定邮箱和手机立即绑定

为什么带有填充字段的结构工作得更快

为什么带有填充字段的结构工作得更快

Go
慕勒3428872 2021-07-01 17:57:28
我刚刚找到了这个库,它提供了无锁环,它的运行速度比通道快: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%。怎么可能?如果有人解释为什么这种无锁算法比通道快得多,甚至是缓冲的,也很感激?
查看完整描述

2 回答

?
jeck猫

TA贡献1909条经验 获得超7个赞

填充通过将每个结构放在自己的缓存行上来消除错误共享。如果两个变量共享一个缓存行,如果有对另一个变量的干预写入,则读取未修改的变量将与读取修改的变量一样昂贵。

当一个变量在多个内核上被读取而不被修改时,缓存行由内核共享。这使得读取非常便宜。在任何内核可以写入该缓存行的任何部分之前,它必须使其他内核上的缓存行无效。如果任何内核稍后从该缓存行读取,它将发现缓存行无效并且必须返回共享它。当一个变量被频繁修改而另一个变量被频繁读取时,这会产生痛苦的额外缓存一致性流量。


查看完整回答
反对 回复 2021-07-05
?
繁星淼淼

TA贡献1775条经验 获得超11个赞

它运行得更快,因为它不需要锁。是 Java 中的一个实现(称为 Disruptor),效果非常好,似乎是 gringo 的灵感来源。他们解释锁的成本,以及如何可以增加吞吐量这里

至于padding,论文也暗示了一些原因。基本上:处理器缓存。这篇论文很好地解释了它。通过让处理器访问其 1 级缓存而不是尽可能频繁地访问内存或其外部缓存,您可以获得巨大的性能提升。但这需要采取额外的预防措施,因为处理器将完全加载其缓存,并在每次需要时重新加载(从内存或 2-3 级缓存)。在并发数据结构的情况下,正如@David Schwartz 所说,错误共享将迫使处理器更频繁地重新加载其缓存,因为一些数据可能会加载到内存行的其余部分中,被修改,并强制整个缓存再次加载。


查看完整回答
反对 回复 2021-07-05
  • 2 回答
  • 0 关注
  • 156 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信