Skip to content

robby031/concurrent-map

Repository files navigation

concurrent-map

Go Reference Go Report Card

A high-performance, thread-safe generic map for Go with a modern sync.Map-style API and an optimized sharded architecture.

Features

Feature Description
API Store / Load / Delete / LoadOrStore / LoadAndDelete / Range - aligned with sync.Map
Hash function Folded-multiply hashing (internal)
Shard selection & shardMask (power-of-two optimized)
Read path Lock-free fast path via atomic.Pointer snapshot
False sharing protection 64-byte cache-line padding per shard
Full scan ParallelRange (parallel shard traversal)
Generics Yes - ConcurrentMap[K, V]

Install

go get github.com/robby031/concurrent-map

Usage

import cmap "github.com/robby031/concurrent-map"

// string key map
m := cmap.New[string]()

// Store a value
m.Store("user:1", "alice")

// Load a value
val, ok := m.Load("user:1")

// Load existing or store new
actual, loaded := m.LoadOrStore("user:1", "bob")

// Load and delete atomically
val, ok = m.LoadAndDelete("user:1")

// Delete
m.Delete("user:2")

// Iterate all entries (sequential, supports early-exit)
m.Range(func(key string, val string) bool {
    fmt.Println(key, val)
    return true // return false to stop early
})

// Iterate all entries (parallel, no early-exit - f must be goroutine-safe)
m.ParallelRange(func(key string, val string) {
    fmt.Println(key, val)
})

// Count entries
n := m.Count()

// Clear all entries
m.Clear()

// JSON marshal / unmarshal
data, _ := json.Marshal(m)
json.Unmarshal(data, &m)

Custom key types

// Any comparable type with a custom shard function
m := cmap.NewWithCustomShardingFunction[uint32, string](func(key uint32) uint32 {
    return key
})

// Types implementing fmt.Stringer
type UserID int
func (u UserID) String() string { return strconv.Itoa(int(u)) }

m := cmap.NewStringer[UserID, string]()

Shard count

Default is 32. Must be a positive power of 2. Set before creating a map:

cmap.SHARD_COUNT = 64
m := cmap.New[string]()

Benchmark

go test -bench=. -benchmem on Apple M4 (arm64, 10 cores):

BenchmarkSingleInsertAbsent-10             6,912,354     219 ns/op    107 B/op    3 allocs/op
BenchmarkSingleInsertAbsentSyncMap-10      6,519,684     282 ns/op    125 B/op    3 allocs/op

BenchmarkSingleInsertPresent-10           51,507,672      23.5 ns/op     24 B/op    1 allocs/op
BenchmarkSingleInsertPresentSyncMap-10    50,926,760      23.6 ns/op     48 B/op    1 allocs/op

BenchmarkMultiInsertSame-10                  864,306    1407 ns/op    260 B/op   11 allocs/op
BenchmarkMultiInsertSameSyncMap-10           589,540    2126 ns/op    825 B/op   31 allocs/op

BenchmarkMultiGetSame-10                   6,520,695     184 ns/op     16 B/op    1 allocs/op
BenchmarkMultiGetSameSyncMap-10            6,505,676     183 ns/op     16 B/op    1 allocs/op

BenchmarkMultiGetSetBlock_32_Shard-10      2,399,465     504 ns/op    304 B/op   12 allocs/op
BenchmarkMultiGetSetBlockSyncMap-10        1,888,932     642 ns/op    864 B/op   32 allocs/op

BenchmarkRange-10                             20,392   58890 ns/op     62 B/op    1 allocs/op
BenchmarkParallelRange-10                     38,808   30662 ns/op   1552 B/op   33 allocs/op

BenchmarkHash_Short-10               461,660,534       2.60 ns/op      0 B/op    0 allocs/op
BenchmarkHash_Medium-10              379,528,196       3.17 ns/op      0 B/op    0 allocs/op

Key takeaways:

  • 22% faster than sync.Map for absent-key writes
  • On par with sync.Map for concurrent reads of the same key (lock-free path)
  • 21% faster than sync.Map for mixed read/write workload (32 shards)
  • 34% faster for concurrent same-key writes (sharding eliminates single-mutex bottleneck)
  • ParallelRange is 48% faster than sequential Range for full scans

License

MIT

About

A high-performance, thread-safe generic map for Go.

Topics

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Sponsor this project

Packages

 
 
 

Contributors

Languages