High-performance, thread-safe in-memory cache for Go with expiration support and advanced features.
- β‘ High Performance: Optimized for concurrent access with optional sharding
- π Thread-Safe: All operations protected with RWMutex
- β° Flexible Expiration: Per-item, default, or no expiration
- π§Ή Janitor: Background cleanup with runtime control
- πΎ Serialization: Persist cache to disk using Gob encoding
- π‘οΈ Overflow Protection: Built-in protection for numeric operations
- π High Concurrency: Sharded cache for reduced lock contention (2-4x faster)
- π― Simple API: Intuitive interface, easy to integrate
go get github.com/pzentenoe/go-cachepackage main
import (
"fmt"
"time"
"github.com/pzentenoe/go-cache"
)
func main() {
// Create cache with 5-minute default expiration and 10-minute cleanup
c := cache.New(5*time.Minute, 10*time.Minute)
// Set a value
c.Set("mykey", "myvalue", cache.DefaultExpiration)
// Get a value
if val, found := c.Get("mykey"); found {
fmt.Println("Found:", val)
}
}// Use sharded cache for high-concurrency workloads
sc := cache.NewSharded(5*time.Minute, 10*time.Minute, 32)
// Same API as standard cache
sc.Set("key", "value", cache.DefaultExpiration)
val, found := sc.Get("key")- Getting Started - Installation, basic usage, core concepts
- API Reference - Complete method documentation
- Sharded Cache - High-concurrency usage guide
- Serialization - Persist cache to disk
- Janitor Control - Runtime cleanup management
Runnable examples in examples/:
- Basic Usage - Core operations and expiration
- Sharded Cache - High-concurrency patterns
- Serialization - Save/Load cache data
- Concurrent Operations - Thread-safe operations
- Overflow Protection - Numeric operation safety
- Janitor Control - Runtime cleanup management
Run any example:
cd examples/basic && go run main.go// Set operations
c.Set("key", "value", cache.DefaultExpiration)
c.SetDefault("key", "value")
c.Add("key", "value", 5*time.Minute) // Only if not exists
c.Replace("key", "new", 5*time.Minute) // Only if exists
// Get operations
val, found := c.Get("key")
val, expTime, found := c.GetWithExpiration("key")
// Delete operations
c.Delete("key")
c.DeleteExpired() // Remove expired items
c.Flush() // Remove all itemsAll numeric operations include overflow/underflow protection:
// Increment/Decrement
c.Increment("counter", 1)
c.Decrement("counter", 1)
c.IncrementFloat("price", 5.50)
// Type-safe operations with error handling
result, err := c.IncrementUint64("views", 100)
if err != nil {
// Overflow would occur
}// Save and load cache to/from disk
c.SaveFile("cache.gob")
c.LoadFile("cache.gob")// Runtime cleanup management
c.PauseJanitor()
c.ResumeJanitor()
c.SetJanitorInterval(5 * time.Minute)The latest release adds overflow protection, janitor control, and complete ShardedCache API parity. See CHANGELOG.md for full version history and release notes.
- Suitable for most applications
- Single lock for all operations
- ~500,000 ops/sec with 100 concurrent goroutines
- Recommended for high-concurrency scenarios
- Multiple independent caches with separate locks
- ~2,000,000 ops/sec with 100 concurrent goroutines (4x improvement)
- Configurable shard count (8, 16, 32, 64)
When to use sharded cache:
- β High concurrent read/write operations (100+ goroutines)
- β Lock contention identified in profiling
- β Maximum throughput required
See Sharded Cache Guide for benchmarks and best practices.
All operations are thread-safe and can be called from multiple goroutines:
var wg sync.WaitGroup
for i := 0; i < 100; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
c.Set(fmt.Sprintf("key%d", id), id, cache.DefaultExpiration)
c.Get(fmt.Sprintf("key%d", id))
}(i)
}
wg.Wait()The cache uses interface{} internally, supporting any Go type. Use type assertions when retrieving values:
// Storing values
c.Set("user", User{Name: "Alice"}, cache.DefaultExpiration)
c.Set("count", 42, cache.DefaultExpiration)
// Retrieving with type assertion
if val, found := c.Get("user"); found {
user := val.(User) // Type assertion
fmt.Println(user.Name)
}
// Safe type assertion
if val, found := c.Get("count"); found {
if count, ok := val.(int); ok {
fmt.Println("Count:", count)
}
}For numeric operations, use the built-in increment/decrement methods which handle types safely.
We welcome contributions! Please:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Add tests for new functionality
- Ensure tests pass and coverage is maintained (currently 92.9%):
go test -race ./... # Run with race detector go test -cover ./... # Check coverage
- Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
This project is licensed under the MIT License - see LICENSE file for details.
See CHANGELOG.md for version history and release notes.
- π Documentation
- π¬ Issues
- π Star on GitHub
Thank you for your support! β€οΈ
Pablo Zenteno - pzentenoe
