Golang’s sync.Map internals

Great article on the topic — https://victoriametrics.com/blog/go-sync-map/index.html.
The whole series of articles is solid, so please take a look if you are interested.

Let me share the most important insights.

How it works

Internal structure is:

So it uses 2 maps under the hood — a fast read-only map, and a «dirty» map, guarded by a mutex, where all writes happen.
Both of them store pointers to the same value, so we don’t store the same data twice.

When we write data, a goroutine acquires the lock, and then writes to the dirty map.
When a read occurs, and a value is found in the fast map, we read it lock-free («happy path»). If not, we acquire the lock, and search through the dirty map as well.
When we delete data, we set a value in «read» map to nil. It means data needs to be cleaned from the «dirty» map later. When it’s cleaned from the «dirty» as well, it is set to a special value.

When we fail to find a key in the «read» map, we increment the «misses» counter. When it reaches some threshold, the «dirty» map is promoted to the «read» one.

Conclusion

Sync.Map is not a silver bullet. It was implemented to optimize the read-intensive cases.
If you write too often or even reading keys that do not exist, it could act slower than a simple map+mutex combination.

Similar Posts

LEAVE A COMMENT