A caching library for go that supports multiple keys and various replacement algorithms.
Go Makefile
Switch branches/tags
Nothing to show
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
examples
LICENSE
Makefile
README.md
benchmark.go
benchmark_test.go
lru.go
lru_test.go
multicache.go
multicache_test.go
multicacheitem.go
random.go
replacement.go
replacement_algorithm_test.go
round_robin.go
round_robin_test.go
second_chance.go
second_chance_test.go
time_expire.go
time_expire_test.go

README.md

multicache

GoDoc

A speedy go caching library that supports multiple keys and various replacement algorithms.

Features

  • Support for caching items with multiple keys
  • Lots of common out of the box replacement algorithms
    • LRU
    • Time Expiration
    • Round Robin
    • Random Replace
    • Second Chance
  • Easily benchmark your application's access patterns to find the optimal configuration
  • Custom replacement algorithms supported
  • Very fast (see benchmarks below)
  • Pull and feature requests are welcome!

What makes it fast?

  • String keys make for fast comparisons
  • No dynamic memory allocation (except your keys and values)
  • Cache elements are stored in an array so they are paged together and fit in an L2/L3 cache (unlike linked lists)
  • Algorithms use basic comparisons and integer math
  • Few (if any) external API calls depending on the caching algorithm

Examples

Bare minimal example:

package main

import (
	"fmt"
	"github.com/josephlewis42/multicache"
)

func main() {
	// creates a cache that can hold 10 values
	cache, _ := multicache.NewDefaultMulticache(10)

	cache.Add("foo", 42)                // Add a key value pair
	cache.AddMany(44.009, "bar", "baz") // one value for many keys (value first)

	value, ok := cache.Get("foo")
	fmt.Printf("%v %v\n", value, ok) // 42 true

	value, ok = cache.Get("bar")
	fmt.Printf("%v %v\n", value, ok) // 44.009 true

	// Delete one key and all of the "multikeys" get removed
	cache.Remove("baz")
	value, ok = cache.Get("bar")
	fmt.Printf("%v %v\n", value, ok) // <nil> false
}

Other cool features are described in the examples directory such as:

  • custom removal of elements
  • function callbacks to fill in data when there is a cache miss
  • creating caches with other replacement algorithms
  • creating a time expiring cache

Benchmarks

Speed

All benchmarks are BS; therefore you can modify the parameters in examples/speedtest/speedtest.go to fit your exact system.

Results (sorted for ops/sec):

	NONE            Allocated:     5 kB Operations/Second: 4164141
	Round Robin     Allocated: 24851 kB Operations/Second: 2895037
	LRU             Allocated: 23772 kB Operations/Second: 2758429
	Random          Allocated: 27642 kB Operations/Second: 2727461
	Second Chance   Allocated: 24335 kB Operations/Second: 2689030
	golang-lru      Allocated: 96809 kB Operations/Second: 1741016

	Timed Cache     Allocated: 62517 kB Operations/Second: 1081585
  • NONE is a cache that hits every time.
  • golang-lru is an external lru cache for comparison with this system.
  • Timed Cache checks the time of each element coming out and nixes it if it is old; this causes many calls to time() which slows it considerably.

Results are for a cache that holds 20% of the data, averaged over 10,000 trials, with 80% chance that one of the items in the current cache is going to be accessed again in the next Get() similar to what users would do if they were logged into the system.

Optimality

You can also test the optimality of various algorithms for your workflow using examples/comparison.go. This will give you an idea of how the caches will perform "in the wild". By default, they'll run through various repeat chances (likelihood that an item already in the cache will be the next item gotten).

 70% Chance of Repeat
Optimal Hit Percentage: 0.816000

Algorithm       Hit %      % of optimal
LRU             76.58000   93.84804
Random          73.13000   89.62010
Round Robin     75.82000   92.91667
Second Chance   76.24000   93.43137

The optimality metric is based on Bélády's optimal ratio i.e. the optimal thing to dump from a cache is the one being used farthest from now.