### Install xsync v4 Source: https://context7.com/puzpuzpuz/xsync/llms.txt Import the v4 module path for installation. ```go import "github.com/puzpuzpuz/xsync/v4" ``` ```sh go get github.com/puzpuzpuz/xsync/v4 ``` -------------------------------- ### Run Go Benchmarks and Analyze Results Source: https://github.com/puzpuzpuz/xsync/blob/main/BENCHMARKS.md Commands to execute benchmarks and process the results using benchstat. Ensure you have Go installed and the xsync library available. ```bash $ go test -run='^$' -cpu=1,2,4,8,16,32,64 -bench . -count=30 -timeout=0 | tee bench.txt $ benchstat bench.txt | tee benchstat.txt ``` -------------------------------- ### Get Map Diagnostic Statistics Source: https://context7.com/puzpuzpuz/xsync/llms.txt Stats provides an O(N) diagnostic snapshot of the map's internal structure. This method is intended for debugging and monitoring and should not be used in performance-critical code paths. ```go m := xsync.NewMap[int, int]() for i := range 1000 { m.Store(i, i*2) } s := m.Stats() fmt.Println(s.ToString()) // MapStats{ // RootBuckets: 256 // TotalBuckets: 256 // EmptyBuckets: 56 // Capacity: 1280 // Size: 1000 // Counter: 1000 // CounterLen: 8 // MinEntries: 0 // MaxEntries: 7 // TotalGrowths: 1 // TotalShrinks: 0 // } ``` -------------------------------- ### Basic xsync Map Operations Source: https://context7.com/puzpuzpuz/xsync/llms.txt Illustrates creating a map, storing, loading, and deleting key-value pairs. It also shows how to load or store a value if the key is not present, and load and delete a key atomically. The map can be pre-sized and cleared. ```go package main import ( "fmt" "github.com/puzpuzpuz/xsync/v4" ) func main() { // Basic construction — optionally pre-size or make grow-only m := xsync.NewMap[string, int]( xsync.WithPresize(1024), // pre-allocate for ~1024 entries // xsync.WithGrowOnly(), // never shrink the underlying table ) m.Store("alice", 42) m.Store("bob", 7) if v, ok := m.Load("alice"); ok { fmt.Println("alice:", v) // alice: 42 } actual, loaded := m.LoadOrStore("carol", 99) fmt.Println("carol loaded:", loaded, "value:", actual) // carol loaded: false value: 99 prev, existed := m.LoadAndStore("alice", 100) fmt.Println("alice prev:", prev, "existed:", existed) // alice prev: 42 existed: true prev2, existed2 := m.LoadAndDelete("bob") fmt.Println("bob prev:", prev2, "existed:", existed2) // bob prev: 7 existed: true m.Delete("carol") fmt.Println("size:", m.Size()) // size: 1 m.Clear() fmt.Println("size after clear:", m.Size()) // size after clear: 0 } ``` -------------------------------- ### Create and Use UMPSCQueue in Go Source: https://github.com/puzpuzpuz/xsync/blob/main/README.md Demonstrates creating an unbounded multi-producer single-consumer queue and enqueuing/dequeuing items. Producers can enqueue concurrently without blocking, but consumers must synchronize. ```go q := xsync.NewUMPSCQueue[string]() // producer inserts an item into the queue; doesn't block // safe to invoke from multiple goroutines inserted := q.Enqueue("bar") // consumer obtains an item from the queue // must be called from a single goroutine item := q.Dequeue() // string ``` -------------------------------- ### Benchmark Results: Counter vs. AtomicInt64 Source: https://github.com/puzpuzpuz/xsync/blob/main/BENCHMARKS.md Performance comparison of xsync's Counter and Go's atomic int64 across different CPU core counts. Lower time/op indicates better performance. ```text name time/op Counter 27.3ns ± 1% Counter-2 27.2ns ±11% Counter-4 15.3ns ± 8% Counter-8 7.43ns ± 7% Counter-16 3.70ns ±10% Counter-32 1.77ns ± 3% Counter-64 0.96ns ±10% AtomicInt64 7.60ns ± 0% AtomicInt64-2 12.6ns ±13% AtomicInt64-4 13.5ns ±14% AtomicInt64-8 12.7ns ± 9% AtomicInt64-16 12.8ns ± 8% AtomicInt64-32 13.0ns ± 6% AtomicInt64-64 12.9ns ± 7% ``` -------------------------------- ### Initialize and Use Counter Source: https://github.com/puzpuzpuz/xsync/blob/main/README.md Create a new Counter for efficient int64 increment/decrement operations, especially under high contention. ```go c := xsync.NewCounter() // increment and decrement the counter c.Inc() c.Dec() // read the current value v := c.Value() ``` -------------------------------- ### Create and Use SPSCQueue in Go Source: https://github.com/puzpuzpuz/xsync/blob/main/README.md Shows how to create a bounded single-producer single-consumer queue and perform optimistic enqueue/dequeue operations. Implement a back-off strategy for failed attempts. ```go q := xsync.NewSPSCQueue[string](1024) // producer inserts an item into the queue // optimistic insertion attempt; doesn't block inserted := q.TryEnqueue("bar") // consumer obtains an item from the queue // optimistic obtain attempt; doesn't block item, ok := q.TryDequeue() // string ``` -------------------------------- ### Import xsync v4 Source: https://github.com/puzpuzpuz/xsync/blob/main/README.md Import the latest major version of xsync. Ensure your Go version is at least 1.24. ```go import ( "github.com/puzpuzpuz/xsync/v4" ) ``` -------------------------------- ### Create and Use MPMCQueue in Go Source: https://github.com/puzpuzpuz/xsync/blob/main/README.md Illustrates creating a bounded multi-producer multi-consumer queue with optimistic enqueue/dequeue. Capacity is rounded up to the next power of 2. Consider a large queue size for optimal performance. ```go // capacity is rounded up to the next power of 2 (1000 -> 1024) q := xsync.NewMPMCQueue[string](1000) // producer optimistically inserts an item into the queue // optimistic insertion attempt; doesn't block inserted := q.TryEnqueue("bar") // consumer obtains an item from the queue // optimistic obtain attempt; doesn't block item, ok := q.TryDequeue() // string ``` -------------------------------- ### Initialize and Use Map Source: https://github.com/puzpuzpuz/xsync/blob/main/README.md Create a new concurrent map with generic key and value types. Supports Store, Load, and Size operations. ```go m := xsync.NewMap[string, string]() m.Store("foo", "bar") v, ok := m.Load("foo") s := m.Size() ``` -------------------------------- ### SPSCQueue: Single Producer Single Consumer Queue Source: https://context7.com/puzpuzpuz/xsync/llms.txt Demonstrates the usage of SPSCQueue for a single producer and single consumer. Callers must implement back-off strategies like runtime.Gosched() when TryEnqueue or TryDequeue fail due to the queue being full or empty, respectively. ```go package main import ( "fmt" "runtime" "sync" "github.com/puzpuzpuz/xsync/v4" ) func main() { q := xsync.NewSPSCQueue[string](1024) var wg sync.WaitGroup wg.Add(2) // Single producer go func() { defer wg.Done() for i := 0; i < 10; i++ { msg := fmt.Sprintf("msg-%d", i) for !q.TryEnqueue(msg) { runtime.Gosched() // back-off: queue is full } } }() // Single consumer go func() { defer wg.Done() received := 0 for received < 10 { if item, ok := q.TryDequeue(); ok { fmt.Println("got:", item) received++ } else { runtime.Gosched() // back-off: queue is empty } } }() wg.Wait() } ``` -------------------------------- ### Use xsync Counter Source: https://context7.com/puzpuzpuz/xsync/llms.txt Demonstrates incrementing, decrementing, and retrieving the value of a striped integer counter. The counter can be reset to zero, but this operation should not occur concurrently. ```go package main import ( "fmt" "sync" "github.com/puzpuzpuz/xsync/v4" ) func main() { c := xsync.NewCounter() var wg sync.WaitGroup // 1000 goroutines each increment and decrement once for i := 0; i < 1000; i++ { wg.Add(1) go func() { defer wg.Done() c.Inc() // increment by 1 c.Add(9) // add arbitrary delta c.Dec() // decrement by 1 }() } wg.Wait() fmt.Println("value:", c.Value()) // 1000 * (1+9-1) = 9000 c.Reset() // reset to zero (no concurrent modifications allowed during reset) fmt.Println("after reset:", c.Value()) // 0 } ``` -------------------------------- ### Basic RBMutex Usage Source: https://github.com/puzpuzpuz/xsync/blob/main/README.md Demonstrates the basic usage of RBMutex for reader and writer locks. Reader locks return a token that must be used for unlocking. ```go mu := xsync.NewRBMutex() // reader lock calls return a token t := mu.RLock() // the token must be later used to unlock the mutex mu.RUnlock(t) // writer locks are the same as in sync.RWMutex mu.Lock() mu.Unlock() ``` -------------------------------- ### MPMCQueue: Multi Producer Multi Consumer Queue Source: https://context7.com/puzpuzpuz/xsync/llms.txt Illustrates the MPMCQueue for multiple producers and consumers. Capacity is rounded up to the next power of two. Implement back-off for non-blocking TryEnqueue/TryDequeue operations. Optimal performance is achieved with a queue capacity significantly larger than the number of concurrent producers/consumers. ```go package main import ( "fmt" "runtime" "sync" "github.com/puzpuzpuz/xsync/v4" ) func main() { // Capacity 1000 is rounded up to 1024 internally q := xsync.NewMPMCQueue[int](1000) const ( numProducers = 4 numConsumers = 4 itemsEach = 100 ) total := numProducers * itemsEach var wg sync.WaitGroup // Multiple producers for p := 0; p < numProducers; p++ { wg.Add(1) go func(id int) { defer wg.Done() for i := 0; i < itemsEach; i++ { val := id*itemsEach + i for !q.TryEnqueue(val) { runtime.Gosched() // queue full, back off } } }(p) } // Multiple consumers results := make(chan int, total) for c := 0; c < numConsumers; c++ { wg.Add(1) go func() { defer wg.Done() for { if item, ok := q.TryDequeue(); ok { results <- item } else { runtime.Gosched() // queue empty, back off } // Stop when channel is full (all items collected) if len(results) == total { return } } }() } wg.Wait() close(results) fmt.Println("collected:", len(results), "items") // collected: 400 items } ``` -------------------------------- ### xsync Map LoadOrCompute Source: https://context7.com/puzpuzpuz/xsync/llms.txt Atomically computes and stores a new value for a key if it doesn't exist. The compute function runs under a bucket lock and should be fast. Passing `cancel = true` aborts insertion. Subsequent calls retrieve the existing value without re-computation. ```go m := xsync.NewMap[string, []string]() // Atomically initialise a slice for a key if absent val, loaded := m.LoadOrCompute("tags", func() ([]string, bool) { return []string{"go", "concurrent"}, false // false = do not cancel }) fmt.Println(loaded, val) // false [go concurrent] // Second call returns the existing value without calling the function val2, loaded2 := m.LoadOrCompute("tags", func() ([]string, bool) { panic("should not be called") }) fmt.Println(loaded2, val2) // true [go concurrent] ``` -------------------------------- ### Counter Operations Source: https://context7.com/puzpuzpuz/xsync/llms.txt Demonstrates the usage of xsync.Counter for concurrent integer counting, including increment, add, decrement, value retrieval, and reset. ```APIDOC ## Counter Operations ### Description `Counter` is a striped `int64` counter that shards its value across multiple cache-line-aligned stripes to avoid contention in high-concurrency scenarios. It offers methods for incrementing, adding arbitrary deltas, decrementing, retrieving the current value, and resetting the counter. ### Methods - **NewCounter()** - Creates and returns a new `Counter`. - **Inc()** - Increments the counter by 1. - **Add(delta int64)** - Adds the specified `delta` to the counter. - **Dec()** - Decrements the counter by 1. - **Value() int64** - Returns the current value of the counter. - **Reset()** - Resets the counter to zero. Note: No concurrent modifications are allowed during reset. ### Example Usage ```go package main import ( "fmt" "sync" "github.com/puzpuzpuz/xsync/v4" ) func main() { c := xsync.NewCounter() var wg sync.WaitGroup // 1000 goroutines each increment and decrement once for i := 0; i < 1000; i++ { wg.Add(1) go func() { defer wg.Done() c.Inc() // increment by 1 c.Add(9) // add arbitrary delta c.Dec() // decrement by 1 }() } wg.Wait() fmt.Println("value:", c.Value()) // 1000 * (1+9-1) = 9000 c.Reset() // reset to zero (no concurrent modifications allowed during reset) fmt.Println("after reset:", c.Value()) // 0 } ``` ``` -------------------------------- ### RBMutex: Reader-Biased Reader/Writer Mutex Source: https://context7.com/puzpuzpuz/xsync/llms.txt Demonstrates RBMutex, a reader-biased mutex. Reader locks are sharded to eliminate contention on the fast path. Writers temporarily disable reader bias. The token returned by RLock/TryRLock must be passed back to RUnlock. ```go package main import ( "fmt" "sync" "github.com/puzpuzpuz/xsync/v4" ) func main() { mu := xsync.NewRBMutex() data := map[string]int{"counter": 0} var wg sync.WaitGroup // Many readers for i := 0; i < 100; i++ { wg.Add(1) go func() { defer wg.Done() t := mu.RLock() // returns *RToken _ = data["counter"] // read-only access mu.RUnlock(t) // must pass the token back }() } // Optimistic (non-blocking) reader wg.Add(1) go func() { defer wg.Done() if locked, t := mu.TryRLock(); locked { _ = data["counter"] mu.RUnlock(t) } }() // Single writer wg.Add(1) go func() { defer wg.Done() mu.Lock() // blocks until all readers release data["counter"]++ mu.Unlock() }() // Optimistic (non-blocking) writer wg.Add(1) go func() { defer wg.Done() if mu.TryLock() { data["counter"] += 10 mu.Unlock() } }() wg.Wait() fmt.Println("counter:", data["counter"]) } ``` -------------------------------- ### Optimistic RBMutex Locking Source: https://github.com/puzpuzpuz/xsync/blob/main/README.md Shows how to use optimistic locking with RBMutex for non-blocking attempts to acquire read or write locks. ```go mu := xsync.NewRBMutex() if locked, t := mu.TryRLock(); locked { // critical reader section... mu.RUnlock(t) } if mu.TryLock() { // critical writer section... mu.Unlock() } ``` -------------------------------- ### Map LoadOrCompute Source: https://context7.com/puzpuzpuz/xsync/llms.txt Explains how to atomically load a value from the map or compute and store it if it doesn't exist. ```APIDOC ## Map LoadOrCompute ### Description `LoadOrCompute` atomically retrieves a value associated with a key. If the key is not found, it computes a new value using the provided function, stores it, and returns it. The compute function is executed while holding the bucket lock, so it should be efficient. The `cancel` parameter in the compute function's return value can be used to abort the insertion. ### Method Signature `LoadOrCompute(key K, compute func() (value V, cancel bool)) (actual V, loaded bool)` - `key K`: The key to look for or insert. - `compute func() (value V, cancel bool)`: A function that computes the value if the key is absent. It returns the computed value and a boolean indicating whether to cancel the insertion. - `actual V`: The existing or newly computed value. - `loaded bool`: True if the value was loaded from the map, false if it was computed and stored. ### Example Usage ```go m := xsync.NewMap[string, []string]() // Atomically initialise a slice for a key if absent val, loaded := m.LoadOrCompute("tags", func() ([]string, bool) { return []string{"go", "concurrent"}, false // false = do not cancel }) fmt.Println(loaded, val) // false [go concurrent] // Second call returns the existing value without calling the function val2, loaded2 := m.LoadOrCompute("tags", func() ([]string, bool) { panic("should not be called") }) fmt.Println(loaded2, val2) // true [go concurrent] ``` ``` -------------------------------- ### Map Basic Operations Source: https://context7.com/puzpuzpuz/xsync/llms.txt Covers the fundamental operations for the generic concurrent Map, including creation, storing, loading, and deleting key-value pairs. ```APIDOC ## Map Basic Operations ### Description `Map[K, V]` is a generic concurrent hash map that is safe for concurrent use by multiple goroutines. It provides methods similar to `sync.Map` and includes additional functionalities. Internally, it uses a cache-line-sized bucket layout (CLHT) for optimized read and write performance, with cooperative parallel rehashing. ### Methods - **NewMap[K, V](options ...MapOption[K, V]) *Map[K, V]** - Creates a new `Map`. Options can include `WithPresize(n int)` to pre-allocate capacity or `WithGrowOnly()` to prevent shrinking. - **Store(key K, value V)** - Stores a key-value pair in the map. - **Load(key K) (value V, ok bool)** - Loads the value associated with a key. Returns the value and a boolean indicating if the key was found. - **LoadOrStore(key K, value V) (actual V, loaded bool)** - Loads the value for a key if it exists, otherwise stores the given value. Returns the existing or newly stored value and a boolean indicating if the value was loaded (true) or stored (false). - **LoadAndStore(key K, value V) (prev V, loaded bool)** - Loads the value for a key and then stores a new value. Returns the previous value and a boolean indicating if the key was present. - **LoadAndDelete(key K) (value V, existed bool)** - Loads the value for a key and then deletes it. Returns the value and a boolean indicating if the key was present. - **Delete(key K)** - Deletes a key-value pair from the map. - **Size() int** - Returns the number of elements in the map. - **Clear()** - Removes all key-value pairs from the map. ### Example Usage ```go package main import ( "fmt" "github.com/puzpuzpuz/xsync/v4" ) func main() { // Basic construction — optionally pre-size or make grow-only m := xsync.NewMap[string, int]( xsync.WithPresize(1024), // pre-allocate for ~1024 entries // xsync.WithGrowOnly(), // never shrink the underlying table ) m.Store("alice", 42) m.Store("bob", 7) if v, ok := m.Load("alice"); ok { fmt.Println("alice:", v) // alice: 42 } actual, loaded := m.LoadOrStore("carol", 99) fmt.Println("carol loaded:", loaded, "value:", actual) // carol loaded: false value: 99 prev, existed := m.LoadAndStore("alice", 100) fmt.Println("alice prev:", prev, "existed:", existed) // alice prev: 42 existed: true prev2, existed2 := m.LoadAndDelete("bob") fmt.Println("bob prev:", prev2, "existed:", existed2) // bob prev: 7 existed: true m.Delete("carol") fmt.Println("size:", m.Size()) // size: 1 m.Clear() fmt.Println("size after clear:", m.Size()) // size after clear: 0 } ``` ``` -------------------------------- ### Convert Map to Plain Go Map Source: https://github.com/puzpuzpuz/xsync/blob/main/README.md Convert an xsync Map to a standard Go map for use with non-concurrent operations. ```go m := xsync.NewMap[int, int]() m.Store(42, 42) pm := xsync.ToPlainMap(m) ``` -------------------------------- ### Convert Map Snapshot to Plain Go Map Source: https://context7.com/puzpuzpuz/xsync/llms.txt ToPlainMap creates a snapshot of the map's current state as a standard Go map. Ensure the source map is not modified concurrently during this operation. ```go m := xsync.NewMap[int, string]() m.Store(1, "one") m.Store(2, "two") pm := xsync.ToPlainMap(m) fmt.Println(pm) // map[1:one 2:two] ``` -------------------------------- ### Iterate Map Entries Lock-Free Source: https://context7.com/puzpuzpuz/xsync/llms.txt RangeRelaxed offers faster, lock-free iteration but may visit keys multiple times if concurrently modified. AllRelaxed provides Go 1.23+ iterator syntax. ```go m := xsync.NewMap[string, int]() m.Store("x", 10) m.Store("y", 20) m.RangeRelaxed(func(key string, value int) bool { fmt.Printf("key=%s value=%d\n", key, value) return true }) // Go 1.23+ iterator syntax for k, v := range m.AllRelaxed() { _ = k _ = v } ``` -------------------------------- ### Iterate Map with Relaxed Consistency Source: https://github.com/puzpuzpuz/xsync/blob/main/README.md Perform lock-free iteration over the map. Note that entries may be visited more than once if modified concurrently. ```go m.RangeRelaxed(func(key int, value int) bool { // process entry return true // continue iteration }) ``` -------------------------------- ### Iterate Map Entries Consistently Source: https://context7.com/puzpuzpuz/xsync/llms.txt Use Range for consistent iteration over map entries, acquiring per-bucket locks. For Go 1.23+, All wraps Range for use with the `range` keyword. ```go m := xsync.NewMap[string, int]() m.Store("a", 1) m.Store("b", 2) m.Store("c", 3) sum := 0 m.Range(func(key string, value int) bool { sum += value return true // return false to stop early }) fmt.Println("sum:", sum) // sum: 6 // Go 1.23+ iterator syntax for k, v := range m.All() { fmt.Printf("%s=%d\n", k, v) } ``` -------------------------------- ### Atomically Compute Map Entry Source: https://context7.com/puzpuzpuz/xsync/llms.txt Use Compute for atomic read-modify-write operations on a single map key. The callback function determines the new value and operation (Update, Delete, Cancel). ```go package main import ( "fmt" "github.com/puzpuzpuz/xsync/v4" ) func main() { counts := xsync.NewMap[string, int]() // Atomically increment a counter (create if absent) inc := func(key string) { counts.Compute(key, func(old int, loaded bool) (int, xsync.ComputeOp) { return old + 1, xsync.UpdateOp }) } inc("hits") inc("hits") inc("hits") v, ok := counts.Compute("hits", func(old int, loaded bool) (int, xsync.ComputeOp) { if old > 2 { return 0, xsync.DeleteOp // remove when threshold exceeded } return old, xsync.CancelOp }) fmt.Println("v:", v, "present:", ok) // v: 3 present: false // Propagating errors out of Compute var computeErr error counts.Compute("new_key", func(old int, loaded bool) (int, xsync.ComputeOp) { if someCondition := true; someCondition { computeErr = fmt.Errorf("aborting compute") return 0, xsync.CancelOp } return 1, xsync.UpdateOp }) fmt.Println("err:", computeErr) // err: aborting compute } ``` -------------------------------- ### Delete Map Entries Matching a Predicate Source: https://context7.com/puzpuzpuz/xsync/llms.txt DeleteMatching iterates under per-bucket locks to remove entries that satisfy a given condition. It returns the count of deleted entries and is suitable for bulk cache invalidation. ```go m := xsync.NewMap[string, int]() m.Store("alice", 10) m.Store("bob", 20) m.Store("carol", 30) m.Store("dave", 40) deleted := m.DeleteMatching(func(key string, value int) (del, stop bool) { return value > 25, false // delete entries with value > 25; never stop early }) fmt.Println("deleted:", deleted) // deleted: 2 fmt.Println("size:", m.Size()) // size: 2 ``` -------------------------------- ### Unbounded Multi-Producer Single-Consumer Queue Source: https://context7.com/puzpuzpuz/xsync/llms.txt UMPSCQueue is an unbounded queue safe for multiple producers but only one consumer. Enqueue operations never block, while Dequeue blocks until an item is available. ```go package main import ( "fmt" "sync" "github.com/puzpuzpuz/xsync/v4" ) func main() { q := xsync.NewUMPSCQueue[int]() var wg sync.WaitGroup // Multiple producers for i := 0; i < 5; i++ { wg.Add(1) go func(n int) { defer wg.Done() q.Enqueue(n) // never blocks, never fails }(i) } // Single consumer — collect exactly 5 items results := make([]int, 5) done := make(chan struct{}) go func() { for i := range 5 { results[i] = q.Dequeue() // blocks until item is available } close(done) }() wg.Wait() <-done fmt.Println("received", len(results), "items") } ``` -------------------------------- ### Delete Matching Entries from Map Source: https://github.com/puzpuzpuz/xsync/blob/main/README.md Remove entries from the map based on a condition. Useful for clearing stale cache entries. ```go m.DeleteMatching(func(key int, value int) (delete, stop bool) { return key%2 == 0, false // delete even keys }) ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.