go-cache
GitHub Overview
patrickmn/go-cache
An in-memory key:value store/cache (similar to Memcached) library for Go, suitable for single-machine applications.
Topics
Star History
Cache Library
go-cache
Overview
go-cache (patrickmn/go-cache) is an in-memory key:value store/cache library for Go, similar to memcached. It's suitable for applications running on a single machine and is essentially a thread-safe map[string]interface{} with expiration times.
Details
go-cache is very simple and fast because it doesn't need to serialize or transmit its contents over the network. Any object can be stored, for a given duration or forever, and the cache can be safely used by multiple goroutines. The entire cache can be saved to and loaded from a file to recover from downtime quickly.
Internally, it can be configured with a default expiration time (e.g., 5 minutes) and cleanup interval (e.g., 10 minutes), periodically removing expired items. It provides simple yet practical functionality and is a very user-friendly cache solution for Go developers.
Pros and Cons
Pros
- Simple and intuitive API design
- Thread-safe, safely accessible from multiple goroutines
- Memcached-like user experience
- Fast operation without network serialization
- Can store arbitrary Go objects
- Automatic expired item removal
- File save/load functionality for downtime recovery
- Optimal for single-machine applications
Cons
- Single-machine limitation (no distributed cache support)
- Limited functionality compared to other cache systems (Redis, Memcached, etc.)
- Not suitable for large-scale data or complex cache strategies
- Few detailed memory usage control features
- No network access capability
Reference Links
Code Examples
Basic Setup
package main
import (
"fmt"
"time"
"github.com/patrickmn/go-cache"
)
func main() {
// Create cache with 5 minute default expiration and 10 minute cleanup interval
c := cache.New(5*time.Minute, 10*time.Minute)
}
Basic Set/Get Operations
// Store string
c.Set("username", "john_doe", cache.DefaultExpiration)
// Store arbitrary object
user := map[string]interface{}{
"id": 123,
"name": "John Doe",
"email": "[email protected]",
}
c.Set("user:123", user, cache.DefaultExpiration)
// Get value
username, found := c.Get("username")
if found {
fmt.Printf("Username: %s\n", username.(string))
}
// Get with type assertion
if userData, found := c.Get("user:123"); found {
if userMap, ok := userData.(map[string]interface{}); ok {
fmt.Printf("User: %v\n", userMap)
}
}
Expiration Time Specification
// Expire after 1 hour
c.Set("temp_data", "temporary", 1*time.Hour)
// Store permanently (no expiration)
c.Set("config", "permanent_value", cache.NoExpiration)
// Use default expiration
c.Set("default_ttl", "uses_default", cache.DefaultExpiration)
// Expire after 10 seconds
c.Set("short_lived", "quick_access", 10*time.Second)
Add and Increment Operations
// Add only if key doesn't exist
err := c.Add("counter", 1, cache.DefaultExpiration)
if err != nil {
fmt.Printf("Key already exists: %v\n", err)
}
// Increment numeric value
c.Set("views", 100, cache.DefaultExpiration)
newValue, err := c.Increment("views", 1)
if err == nil {
fmt.Printf("New view count: %d\n", newValue)
}
// Decrement
newValue, err = c.Decrement("views", 5)
if err == nil {
fmt.Printf("Decremented view count: %d\n", newValue)
}
// Increment float64
c.Set("score", 10.5, cache.DefaultExpiration)
newScore, err := c.IncrementFloat("score", 2.3)
if err == nil {
fmt.Printf("New score: %.2f\n", newScore)
}
Cache Management Operations
// Delete item
c.Delete("username")
// Check key existence (with expiration check)
_, found := c.Get("user:123")
fmt.Printf("User exists: %t\n", found)
// Get all items
items := c.Items()
fmt.Printf("Total items: %d\n", len(items))
// Manually delete expired items
c.DeleteExpired()
// Clear entire cache
c.Flush()
Expiration Check and Update
// Check item expiration
if item, found := c.get("user:123"); found {
fmt.Printf("Expires at: %v\n", item.Expiration)
}
// Update expiration (maintain existing value, change only expiration)
if currentValue, found := c.Get("user:123"); found {
c.Set("user:123", currentValue, 2*time.Hour) // Extend to 2 hours
}
// TTL implementation (using Go standard library)
func getTTL(c *cache.Cache, key string) time.Duration {
if item, found := c.get(key); found {
if item.Expiration > 0 {
return time.Until(time.Unix(0, item.Expiration))
}
return -1 // NoExpiration
}
return 0 // Not found
}
File Save and Restore
// Save cache to file
items := c.Items()
err := saveToFile("cache_backup.gob", items)
if err != nil {
fmt.Printf("Save error: %v\n", err)
}
// Restore cache from file
items, err := loadFromFile("cache_backup.gob")
if err != nil {
fmt.Printf("Load error: %v\n", err)
} else {
// Create new cache with restored items
restoredCache := cache.NewFrom(cache.DefaultExpiration, 10*time.Minute, items)
}
// File save helper function example
func saveToFile(filename string, items map[string]cache.Item) error {
// Serialize using encoding/gob or json
// Implementation depends on specific requirements
return nil
}
Configuration and Customization
// Custom cleanup interval
c := cache.New(30*time.Minute, 1*time.Minute) // Cleanup every minute
// Disable cleanup (manual management)
c := cache.New(30*time.Minute, -1)
// Custom callback functionality (pseudo-implementation)
c.OnEvicted(func(key string, value interface{}) {
fmt.Printf("Evicted: %s = %v\n", key, value)
})
// Usage statistics tracking (requires custom implementation)
type StatsCache struct {
*cache.Cache
hits int64
misses int64
}
func (s *StatsCache) Get(key string) (interface{}, bool) {
value, found := s.Cache.Get(key)
if found {
s.hits++
} else {
s.misses++
}
return value, found
}