diff --git a/README.md b/README.md index 57fdadf..c2969a7 100644 --- a/README.md +++ b/README.md @@ -62,6 +62,30 @@ func main() { Run this example with `go run examples/main.go`. +## Performance Comparison +Comparison of performance with original [go-cache](https://github.com/patrickmn/go-cache) implementation. + +Spoiler alert! The difference is insignificant. + + + +| Test | [Non generic](https://github.com/patrickmn/go-cache)| | This version | | +|----------------------------------------------|-----------|-------------|-----------|---------------| +| BenchmarkCacheGetStringExpiring-8 | 29884011 | 41.45 ns/op | 28318041 | 43.31 ns/op | +| BenchmarkCacheGetStringNotExpiring-8 | 91891774 | 14.20 ns/op | 72259294 | 14.02 ns/op | +| BenchmarkCacheGetConcurrentExpiring-8 | 26299849 | 42.58 ns/op | 30129078 | 39.53 ns/op | +| BenchmarkCacheGetConcurrentNotExpiring-8 | 28991383 | 41.25 ns/op | 30760544 | 38.09 ns/op | +| BenchmarkCacheGetManyConcurrentExpiring-8 | 55589712 | 44.90 ns/op | 56991110 | 38.86 ns/op | +| BenchmarkCacheGetManyConcurrentNotExpiring-8 | 30105078 | 43.98 ns/op | 46270045 | 41.54 ns/op | +| BenchmarkCacheSetStringExpiring-8 | 18392893 | 63.41 ns/op | 17788724 | 61.42 ns/op | +| BenchmarkCacheSetStringNotExpiring-8 | 46400654 | 28.45 ns/op | 40226074 | 27.41 ns/op | +| BenchmarkCacheSetDelete-8 | 18703620 | 60.75 ns/op | 18270448 | 59.90 ns/op | +| BenchmarkCacheSetDeleteSingleLock-8 | 32633755 | 39.34 ns/op | 32415156 | 36.96 ns/op | +| BenchmarkCacheGetStructExpiring-8 | 30487856 | 41.60 ns/op | 26925226 | 40.55 ns/op | +| BenchmarkCacheGetStructNotExpiring-8 | 91921044 | 13.94 ns/op | 96379750 | 13.08 ns/op | +| BenchmarkCacheSetStructExpiring-8 | 13977464 | 86.44 ns/op | 13364509 | 87.69 ns/op | +| BenchmarkCacheSetStructNotExpiring-8 | 22749384 | 54.14 ns/op | 23207397 | 52.58 ns/op | + ### Reference `godoc` or [http://godoc.org/github.com/num30/go-cache](http://godoc.org/github.com/num30/go-cache) diff --git a/bench_test.go b/bench_test.go new file mode 100644 index 0000000..d201a13 --- /dev/null +++ b/bench_test.go @@ -0,0 +1,15 @@ +package cache + +type BenchStr struct { + Num int + String string +} + +//func Benchmark_CacheGet(b *testing.B) { +// c := New[*BenchStr](DefaultExpiration, 0) +// c.Set("foo", &BenchStr{1, "bar"}, DefaultExpiration) +// +// for i := 0; i < b.N; i++ { +// c.Get("foo") +// } +//} diff --git a/cache_test.go b/cache_test.go index 3d9ed73..f1f5961 100644 --- a/cache_test.go +++ b/cache_test.go @@ -2,13 +2,14 @@ package cache import ( "bytes" - "github.com/stretchr/testify/assert" "io/ioutil" "runtime" "strconv" "sync" "testing" "time" + + "github.com/stretchr/testify/assert" ) type TestStruct struct { @@ -346,15 +347,15 @@ func TestSerializeUnserializable(t *testing.T) { } } -func BenchmarkCacheGetExpiring(b *testing.B) { - benchmarkCacheGet(b, 5*time.Minute) +func BenchmarkCacheGetStringExpiring(b *testing.B) { + benchmarkCacheGetString(b, 5*time.Minute) } -func BenchmarkCacheGetNotExpiring(b *testing.B) { - benchmarkCacheGet(b, NoExpiration) +func BenchmarkCacheGetStringNotExpiring(b *testing.B) { + benchmarkCacheGetString(b, NoExpiration) } -func benchmarkCacheGet(b *testing.B, exp time.Duration) { +func benchmarkCacheGetString(b *testing.B, exp time.Duration) { b.StopTimer() tc := New[string](exp, 0) tc.Set("foo", "bar", DefaultExpiration) @@ -495,15 +496,15 @@ func benchmarkCacheGetManyConcurrent(b *testing.B, exp time.Duration) { wg.Wait() } -func BenchmarkCacheSetExpiring(b *testing.B) { - benchmarkCacheSet(b, 5*time.Minute) +func BenchmarkCacheSetStringExpiring(b *testing.B) { + benchmarkCacheSetString(b, 5*time.Minute) } -func BenchmarkCacheSetNotExpiring(b *testing.B) { - benchmarkCacheSet(b, NoExpiration) +func BenchmarkCacheSetStringNotExpiring(b *testing.B) { + benchmarkCacheSetString(b, NoExpiration) } -func benchmarkCacheSet(b *testing.B, exp time.Duration) { +func benchmarkCacheSetString(b *testing.B, exp time.Duration) { b.StopTimer() tc := New[string](exp, 0) b.StartTimer() @@ -638,3 +639,43 @@ func TestGetWithExpiration(t *testing.T) { assert.Equal(t, expiration.UnixNano(), tc.items["e"].Expiration, "expiration for e is not the correct time") assert.Greater(t, expiration.UnixNano(), time.Now().UnixNano(), "expiration for e is in the past") } + +// Benchmark struct + +func BenchmarkCacheGetStructExpiring(b *testing.B) { + benchmarkCacheGetStruct(b, 5*time.Minute) +} + +func BenchmarkCacheGetStructNotExpiring(b *testing.B) { + benchmarkCacheGetStruct(b, NoExpiration) +} + +func benchmarkCacheGetStruct(b *testing.B, exp time.Duration) { + b.StopTimer() + tc := New[*TestStruct](exp, 0) + + tc.Set("foo", &TestStruct{Num: 1}, DefaultExpiration) + b.StartTimer() + for i := 0; i < b.N; i++ { + st, _ := tc.Get("foo") + // just do something + st.Num++ + } +} + +func BenchmarkCacheSetStructExpiring(b *testing.B) { + benchmarkCacheSetStruct(b, 5*time.Minute) +} + +func BenchmarkCacheSetStructNotExpiring(b *testing.B) { + benchmarkCacheSetStruct(b, NoExpiration) +} + +func benchmarkCacheSetStruct(b *testing.B, exp time.Duration) { + b.StopTimer() + tc := New[*TestStruct](exp, 0) + b.StartTimer() + for i := 0; i < b.N; i++ { + tc.Set("foo", &TestStruct{Num: 1}, DefaultExpiration) + } +}