go sync:使用不相交的新键减少Map操作之间的争用

hfsqlsce  于 7个月前  发布在  Go
关注(0)|答案(8)|浏览(86)

Go 1.9实现的sync.Map使用单个Mutex来保护包含新键的读写Map。这使得Store具有不同新键的调用总是相互竞争,也与具有不同新键的Load调用相互竞争,即使每个键的LoadStore仅限于单个线程。

这对于标准库中的sync.Map用例并不重要,因为它们在稳定状态下不操作新键,但它限制了sync.Map在涉及高周转率的用例中的实用性。这些用例可能包括:

  • 具有高驱逐率的缓存,例如前端键值存储服务的缓存
  • RPC或HTTP流ID到处理程序状态的Map
  • 将不透明句柄Map到Go指针以编写符合cgo指针传递规则的C导出API

我们应该探索解决新键竞争的方法,例如对读写Map和相关锁进行分片(如#20360建议的那样),记录写入操作(并使用布隆过滤器或HyperLogLog过滤器避免读取日志,类似于#21032的建议),或者将读写Map存储在原子树数据结构中,而不是内置的map

xtfmy6hx

xtfmy6hx1#

(@orcaman 和/或 @OneOfOne 可能对这个感兴趣?)

hc2pp10m

hc2pp10m2#

我对这个想法很感兴趣,但我现在不能承诺。我脑海中浮现的一个想法需要破解运行时/哈希Map*,否则我们必须对键进行双重哈希。

w1jd8yoj

w1jd8yoj3#

非常有趣的任务,我很想接手这个。我认为它应该可以在Go1.10里程碑上实现。在我能100%承诺在适当的时候完成这个之前,我会再多考虑一下设计。

oxiaedzo

oxiaedzo4#

@orcaman What I wanted to do is something like https://github.com/OneOfOne/cmap/tree/master/v2 ,
I use a slightly modified version of this in my code, but I wanted to do that with sync.Map in a way, but that'd require a lot more runtime knowledge to be able to use runtime/map's hasher directly to do the sharding rather than double hash it.
Sadly I don't have the knowledge nor time to learn the internals of runtime/map right now.
By all means if you can do that, it'd be great or we can discuss it.

// very simple set/get benchmark using cmap, rwmutex map and sync.Map.

BenchmarkCMap/128-8     20000000               105 ns/op               0 B/op          0 allocs/op
BenchmarkCMap/256-8     20000000                88.6 ns/op             0 B/op          0 allocs/op
BenchmarkCMap/512-8     20000000                67.6 ns/op             0 B/op          0 allocs/op
BenchmarkCMap/1024-8    30000000                42.3 ns/op             0 B/op          0 allocs/op
BenchmarkCMap/2048-8    30000000                34.5 ns/op             0 B/op          0 allocs/op
BenchmarkCMap/4096-8    50000000                33.0 ns/op             0 B/op          0 allocs/op
BenchmarkMutexMap-8     10000000               196 ns/op               0 B/op          0 allocs/op
BenchmarkSyncMap-8      30000000                39.3 ns/op            16 B/op          1 allocs/op
w41d8nur

w41d8nur5#

我认为你可以使用锁片和脏Map,低位哈希值执行选择 - 但这需要访问内部哈希码。

ds97pgxw

ds97pgxw6#

@bcmills 我愿意尝试一下。有没有描述在实现是标准库一部分时使用内部设施的文档?

z6psavjg

z6psavjg7#

我不知道有没有好的入门文档,但也许@randall77或@aclements可以给你指明方向。

kd3sttzy

kd3sttzy8#

这真是个好主意。

相关问题