sync.Map performance problem

1,442 views
Skip to first unread message

barce show

unread,
Oct 21, 2017, 9:54:24 AM10/21/17
to golang-nuts
I use sync.Map in my program to support access concurrently, but witin two hours with less than 50 clients, my program run out all of my cpu, so I go back to read the pkg document, and I find this sentence


"For use cases that do not share these attributes, it will likely have comparable or worse performance and worse type safety than an ordinary map paired with a read-write mutex."

maybe this the my problem, but I don't really understand what it represent
can anybody help me?

barce show

unread,
Oct 21, 2017, 9:54:24 AM10/21/17
to golang-nuts
how to understand this sentence

Val

unread,
Oct 21, 2017, 4:32:07 PM10/21/17
to golang-nuts
Hi Barce

For the CPU going wild, it would be best to share the code (if you can't share the whole project, then a relevant part of it that is runnable and exhibits the perf problem). There are many possible problems that could cause this, it is not self-evident that the use of sync.Map is the problem.

For the sync.Map documentation, it basically says that this new Map type introduced in Go 1.9 is useful in some specific cases, but not very useful in other cases.
The set of conditions for sync.Map to be useful and performant are (all must be true):
- "concurrent loops" : you have multiple goroutines accessing the Map, each within its own loop ;
- "keys that are stable over time" : e.g. strings are very stable,  custom structs whose contents changes are not ;
- "either few steady-state stores, or stores localized to one goroutine per key" : e.g. when distinct goroutines almost always write distinct entries (different keys).

The part of doc that says "...than an ordinary map paired with a read-write mutex." means that in some cases, it is a better idea to use the built-in (non-concurrent-safe) map type, but to carefully lock a RWMutex before each access, which prevents data races.

Cheers
Val

Konstantin Khomoutov

unread,
Oct 25, 2017, 3:31:04 AM10/25/17
to barce show, golang-nuts
On Fri, Oct 20, 2017 at 11:50:42PM -0700, barce show wrote:

> I use sync.Map in my program to support access concurrently, but witin two
> hours with less than 50 clients, my program run out all of my cpu, so I go
> back to read the pkg document, and I find this sentence
>
> "For use cases that do not share these attributes, it will likely have
> comparable or worse performance and worse type safety than an ordinary map
> paired with a read-write mutex."

You seem to omit the key point from the description [1], which is

| It is optimized for use in concurrent loops with keys that are stable
| over time, and either few steady-state stores, or stores localized to
| one goroutine per key.

I dare to "translate" this into more layman's language in the following
way:

the sync.Map is optimized for the use cases where the following
two conditions are met:

1. The keys in the map are mostly stable. That is, there is no
constant churn of the keys — insertions and deletions, — but rather
reads and updates.

2. There is not much stores (into the same keys, mostly, — see above)
compared to the number of reads
- or -
such stores are performed by the same goroutine, — that is, each
goroutine updates the data under its own key, and no other
goroutine does that, or does this infrequently.

From this, we may gather that the implementation of sync.Map supposedly
uses a couple of tricks which are more involved than just having a
single sync.RWMutex under the hood. The implementation goes to those
lengths to improve the performance for the cases outlined above but, as
with all things related to optimizations, it sucks performance-wise for
the cases which do not fit into the intended usage pattern.

You can see this even with the simple locks: the sync.RWMutex allows
multiple parattel readers and only goes exclusive for a writer but the
payback is the implementation slower than sync.Mutex which is
all-exclusive, and so if you have roughly equal numbers of readers and
writers sync.RWMutex may actually work slower for your case.

> maybe this the my problem, but I don't really understand what it represent
> can anybody help me?

May I ask whether you have actually profiled your problem?
Are you sure that's sync.Map which affects your performance, and not
something else completely?

Go comes packed with a slew of tools to profile your programs.
You should start with the CPU profile and block profile.
There are lots of information on how to start with profiling the Go code
so just use your favourite search engine to get started.

1. https://golang.org/pkg/sync/#Map

Reply all
Reply to author
Forward
0 new messages