Go implementation of Python's defaultdict
,
in a way that's both thread-safe and memory efficient.
Underneath it pairs a sync.Map
with a sync.Pool
,
and removed all direct store/write accesses to the map.
As a result, the only way to mutate the map is through Load
/Get
,
(which either create a new value for you if this is the first access to the key,
or return the value created by a previous Load
/Get
),
then mutate the value returned directly (in a thread-safe way).
Here are 2 example usages:
-
To implement a rowlock. See my rowlock package for detailed example.
-
To implement a concurrent counter-by-key. See package example or below for details.
Here's a step-by-step example to create a concurrent counter-by-key.
First, create a generator,
which simply returns an *int64
so it can be used by atomic int64 functions:
generator := func() defaultdict.Pointer {
return new(int64)
}
Then, create the map:
m := defaultdict.New(generator)
When you need to add the counter, get by key then use atomic.AddInt64
:
atomic.AddInt64(m.Get(key).(*int64), 1)
When you need to get the counter value,
just get by key then use atomic.LoadInt64
:
fmt.Printf(
"Key %v was added %d times\n",
key,
atomic.LoadInt64(
m.Get(key).(*int64),
),
)
Or use Range
:
m.Range(func(key defaultdict.Comparable, value defaultdict.Pointer) bool {
fmt.Printf("Key %v was added %d times\n", key, atomic.LoadInt64(value.(*int64)))
return true
})