Open pelicans45 opened 1 year ago
Hi,
xsync.Map
doesn't have drawbacks when compared with sync.Map
or at least I'm not aware of them. But in certain niche use cases, a plain map
protected with a mutex may be a better choice. See https://github.com/puzpuzpuz/xsync/issues/94#issuecomment-1500807151 for more details.
I have a usecase where I found no reason to switch from the standard library's sync.Map
: https://github.com/mgnsk/evcache/pull/35
@puzpuzpuz I guess I'll need to do some testing
@mgnsk Interesting. Not sure how much of a difference it might make, but In my case I was thinking of using xsync.Map
rather than xsync.MapOf
.
@mgnsk the only parallel benchmark you have has a contention point that kills the scalability of operations in both sync.Map
and xsync.Map
: https://github.com/mgnsk/evcache/blob/5e3f071a8d4be4eabddb0fb227d24121163e8741/cache_test.go#L302
Also, you always evict the same key which looks very artificial. Finally, you're using a mutex in Evict
and PushBack
methods (I didn't check others), so probably that's why a different concurrent map doesn't make any difference - the overhead of synchronization and other data structures is much more noticeable.
@65947689564 first of all, I advise you to write benchmarks that are close enough to your use case rather than trust benchmarks in xsync
or any other repository.
In general, sync.Map
has very similar scalability characteristics to xsync.Map
when it comes to read operations. Both don't use mutexes when reading data. But write operation scalability is very different: sync.Map
uses a single mutex in many cases when it comes to the map mutation leading to blocked reads.
See https://github.com/golang/go/blob/13529cc5f443ef4e242da3716daa0032aa8d34f2/src/sync/map.go for more details. As for xsync.Map
, this post explains how it works (the current design is slightly different).
As a rule of thumb, if your map never or almost never mutates, both sync.Map
and xsync.Map
should be on par. On the other hand, if it never mutates, you should go for a plain map
which doesn't involve atomic operations and has plain memory layout. As for xsync.Map
vs. xsync.MapOf
, MapOf
is a better choice since it doesn't use intermediate interface{}
structs.
See #102 example of sync.Map
performing better xsync.MapOf
(in a fairly specific use-case).
I have an application that makes use of a lot of different
sync.Map
s. It mostly fits the recommended use case forsync.Map
("append-only maps" with a lot more reads than writes), but the benchmarks forxsync.Map
do look better across the board, so I was thinking of maybe just swapping them all out. I see your blog post mentions "When it comes to reads which are the strongest point ofsync.Map
, both data structures are on par.", though in the repo README you say "Due to this design, in all considered scenariosMap
outperformssync.Map
."Just wondering if you can foresee any reason to not do this. This blog post mentions potential memory concerns, but I think that probably won't be an issue for me.