Live data from Hacker News

Benchmarks for concurrent hash map implementations in Go

github.com

21–27 of 27 posts

Re: Benchmarks for concurrent hash map implementations in Go

#21

Idk why but I tend to shy away from non std libs that use unsafe (like xsync). I'm sure the code is fine, but I'd rather take the performance hit I guess.

Unsafe usage in the recent xsync versions is very limited (runtime.cheaprand only). On the other hand, your point is valid and it'd be great to see standard library improvements.

Re: Benchmarks for concurrent hash map implementations in Go

#22

I don't write Go but respect to the author for trying to list trade-off considerations for each of the implementations tested, and not just proclaim their library the overal winner.

Thanks. There are downsides in each approach, e.g. if you care about minimal allocation rate, you should go with plain map + RWMutex. So yeah, no silver bullet.

Re: Benchmarks for concurrent hash map implementations in Go

#23
post #7

I ran benchmarks comparing xsync.Map's memory allocation against orcaman/concurrent-map. Pure overwrite workload (pre-allocated values): xsync.Map: 24 B/op 1 alloc/op 31.89 ns/op orcaman/concurrent-map: 0 B/op 0 alloc/op 70.72 ns/op Real-world mixed (80% overwrites, 20% new): xsync.Map: 57 B/op 2 allocs/op 218.1 ns/op orcaman/concurrent-map: 63 B/op 3 allocs/op 283.1 ns/op Go maps reuse memory on overwrites, which is…

Allocation rates comparison is included. If your application writes into the map most of the time, you should go with plain map + RWMutex (or orcaman/concurrent-map). But if, for instance, you're using the map as a cache, read operations will dominate and having better read scalability becomes important. As an example, Otter cache library uses a modified variant of xsync.Map, not a plain map + RWMutex.

Re: Benchmarks for concurrent hash map implementations in Go

#24
post #12

Orcaman is a very straightforward implementation (just sharded RW locks and backing maps), but it limits the number of shards to a fixed 32. I wonder what the benchmarks would look like if the shard count were increased to 64, 128, etc.

My box is 12c/24t only, so it won't make any difference. But on a beefy box, it may improve performance in high cardinality key scenarios.

It potentially still might make a difference due to reduced contention: if we have more shards the chances of two or more goroutines hitting the same shard would be lower. In my mind the only downside to having more shards is the upfront cost, so it might slow down the smallest example only

Re: Benchmarks for concurrent hash map implementations in Go

#25

Earlier quoted context omitted.

My box is 12c/24t only, so it won't make any difference. But on a beefy box, it may improve performance in high cardinality key scenarios.

It potentially still might make a difference due to reduced contention: if we have more shards the chances of two or more goroutines hitting the same shard would be lower. In my mind the only downside to having more shards is the upfront cost, so it might slow down the smallest example only

The upfront cost isn't that big: a Go map+RW lock is probably a few hundred bytes. Allocating them costs far below 1 ms.

Re: Benchmarks for concurrent hash map implementations in Go

#26

I don't write Go but respect to the author for trying to list trade-off considerations for each of the implementations tested, and not just proclaim their library the overal winner.

Thanks. There are downsides in each approach, e.g. if you care about minimal allocation rate, you should go with plain map + RWMutex. So yeah, no silver bullet.

There almost never is. The fact that you acknowledge it and give context only would make me more confident in trying out your library, or any of the other listed (if I wrote Go code, that is).

Re: Benchmarks for concurrent hash map implementations in Go

#27

Looks good! There's an important thing missing from the benchmarks though: - cpu usage under concurrency: many of these spin-lock or use atomics, which can use up to 100% cpu time just spinning. - latency under concurrency: atomics cause cache-line bouncing which kills latency, especially p99 latency

Yup, that's a valid point. I'll consider adding these metrics.

Am I reading the benchmark code that uses the same prefix for all string keys? This would be pathological for any trie-based implementation.
Post reply on HN