The caching component by default provides a high-speed in-memory cache, with operation efficiency at the ns nanosecond level of CPU performance loss.

Usage Example

Basic Usage

  1. package main
  2. import (
  3. "fmt"
  4. "github.com/gogf/gf/v2/os/gcache"
  5. "github.com/gogf/gf/v2/os/gctx"
  6. )
  7. func main() {
  8. // Create a cache object,
  9. // but you can also conveniently use the gcache package methods directly
  10. var (
  11. ctx = gctx.New()
  12. cache = gcache.New()
  13. )
  14. // Set cache, no expiration
  15. err := cache.Set(ctx, "k1", "v1", 0)
  16. if err != nil {
  17. panic(err)
  18. }
  19. // Get cache value
  20. value, err := cache.Get(ctx, "k1")
  21. if err != nil {
  22. panic(err)
  23. }
  24. fmt.Println(value)
  25. // Get cache size
  26. size, err := cache.Size(ctx)
  27. if err != nil {
  28. panic(err)
  29. }
  30. fmt.Println(size)
  31. // Check if a specific key name exists in the cache
  32. b, err := cache.Contains(ctx, "k1")
  33. if err != nil {
  34. panic(err)
  35. }
  36. fmt.Println(b)
  37. // Remove and return the deleted key-value
  38. removedValue, err := cache.Remove(ctx, "k1")
  39. if err != nil {
  40. panic(err)
  41. }
  42. fmt.Println(removedValue)
  43. // Close the cache object to allow GC to reclaim resources
  44. if err = cache.Close(ctx); err != nil {
  45. panic(err)
  46. }
  47. }

After execution, the output is:

  1. v1
  2. 1
  3. true
  4. v1

Expiration Control

  1. package main
  2. import (
  3. "fmt"
  4. "github.com/gogf/gf/v2/os/gcache"
  5. "github.com/gogf/gf/v2/os/gctx"
  6. "time"
  7. )
  8. func main() {
  9. var (
  10. ctx = gctx.New()
  11. )
  12. // Write when the key name does not exist, set expiration time to 1000 milliseconds
  13. _, err := gcache.SetIfNotExist(ctx, "k1", "v1", time.Second)
  14. if err != nil {
  15. panic(err)
  16. }
  17. // Print current list of key names
  18. keys, err := gcache.Keys(ctx)
  19. if err != nil {
  20. panic(err)
  21. }
  22. fmt.Println(keys)
  23. // Print current list of key-values
  24. values, err := gcache.Values(ctx)
  25. if err != nil {
  26. panic(err)
  27. }
  28. fmt.Println(values)
  29. // Get a specific key value, write if it does not exist, and return the key value
  30. value, err := gcache.GetOrSet(ctx, "k2", "v2", 0)
  31. if err != nil {
  32. panic(err)
  33. }
  34. fmt.Println(value)
  35. // Print current key-value pairs
  36. data1, err := gcache.Data(ctx)
  37. if err != nil {
  38. panic(err)
  39. }
  40. fmt.Println(data1)
  41. // Wait for 1 second, so k1:v1 expires automatically
  42. time.Sleep(time.Second)
  43. // Print current key-value pairs again, and find that k1:v1 has expired, leaving only k2:v2
  44. data2, err := gcache.Data(ctx)
  45. if err != nil {
  46. panic(err)
  47. }
  48. fmt.Println(data2)
  49. }

After execution, the output is:

  1. [k1]
  2. [v1]
  3. v2
  4. map[k1:v1 k2:v2]
  5. map[k2:v2]

GetOrSetFunc*

GetOrSetFunc retrieves a cache value, and if the cache does not exist, executes the specified f func(context.Context) (interface{}, error), caches the result of the f method, and returns that result.

It is important to note that GetOrSetFunc‘s cache method parameter f is executed outside of the cache’s lock mechanism, so GetOrSetFunc can be nested within f. However, if f is computationally intensive, it may be executed multiple times under high concurrency (only the result from the first executed f can be successfully cached, the rest will be discarded). On the other hand, GetOrSetFuncLock‘s cache method f is executed within the cache’s lock mechanism, ensuring that f is executed only once when the cache item does not exist, but the cache write lock duration depends on the execution time of the f method.

Here’s an example:

  1. package main
  2. import (
  3. "fmt"
  4. "github.com/gogf/gf/v2/os/gcache"
  5. "github.com/gogf/gf/v2/os/gctx"
  6. "time"
  7. )
  8. func main() {
  9. var (
  10. ch = make(chan struct{}, 0)
  11. ctx = gctx.New()
  12. key = `key`
  13. value = `value`
  14. )
  15. for i := 0; i < 10; i++ {
  16. go func(index int) {
  17. <-ch
  18. _, err := gcache.GetOrSetFuncLock(ctx, key, func(ctx context.Context) (interface{}, error) {
  19. fmt.Println(index, "entered")
  20. return value, nil
  21. }, 0)
  22. if err != nil {
  23. panic(err)
  24. }
  25. }(i)
  26. }
  27. close(ch)
  28. time.Sleep(time.Second)
  29. }

After execution, the terminal outputs (random, but only one message is output):

  1. 9 entered

You can see that when multiple goroutines concurrently call the GetOrSetFuncLock method, due to its concurrent safety control, only one goroutine‘s value-generation function executes successfully, and once successful, other goroutines immediately return with the data without executing their corresponding value-generation functions.

LRU Cache Eviction Control

  1. package main
  2. import (
  3. "fmt"
  4. "github.com/gogf/gf/v2/os/gcache"
  5. "github.com/gogf/gf/v2/os/gctx"
  6. "time"
  7. )
  8. func main() {
  9. var (
  10. ctx = gctx.New()
  11. cache = gcache.New(2) // Set LRU eviction count
  12. )
  13. // Add 10 elements, no expiration
  14. for i := 0; i < 10; i++ {
  15. if err := cache.Set(ctx, i, i, 0); err != nil {
  16. panic(err)
  17. }
  18. }
  19. size, err := cache.Size(ctx)
  20. if err != nil {
  21. panic(err)
  22. }
  23. fmt.Println(size)
  24. keys, err := cache.Keys(ctx)
  25. if err != nil {
  26. panic(err)
  27. }
  28. fmt.Println(keys)
  29. // Read key name 1 to ensure that this key name is preferentially retained
  30. value, err := cache.Get(ctx, 1)
  31. if err != nil {
  32. panic(err)
  33. }
  34. fmt.Println(value)
  35. // After waiting for some time (checked once per second by default),
  36. // elements will be evicted in order from oldest to newest
  37. time.Sleep(3 * time.Second)
  38. size, err = cache.Size(ctx)
  39. if err != nil {
  40. panic(err)
  41. }
  42. fmt.Println(size)
  43. keys, err = cache.Keys(ctx)
  44. if err != nil {
  45. panic(err)
  46. }
  47. fmt.Println(keys)
  48. }

After execution, the output is:

  1. [2 3 5 6 7 0 1 4 8 9]
  2. 1
  3. 2
  4. [1 9]

Performance Testing

Test Environment

  1. CPU: Intel(R) Core(TM) i5-4460 CPU @ 3.20GHz
  2. MEM: 8GB
  3. SYS: Ubuntu 16.04 amd64

Test Results

  1. john@john-B85M:~/Workspace/Go/GOPATH/src/github.com/gogf/gf/v2/os/gcache$ go test *.go -bench=".*" -benchmem
  2. goos: linux
  3. goarch: amd64
  4. Benchmark_CacheSet-4 2000000 897 ns/op 249 B/op 4 allocs/op
  5. Benchmark_CacheGet-4 5000000 202 ns/op 49 B/op 1 allocs/op
  6. Benchmark_CacheRemove-4 50000000 35.7 ns/op 0 B/op 0 allocs/op
  7. Benchmark_CacheLruSet-4 2000000 880 ns/op 399 B/op 4 allocs/op
  8. Benchmark_CacheLruGet-4 3000000 212 ns/op 33 B/op 1 allocs/op
  9. Benchmark_CacheLruRemove-4 50000000 35.9 ns/op 0 B/op 0 allocs/op
  10. Benchmark_InterfaceMapWithLockSet-4 3000000 477 ns/op 73 B/op 2 allocs/op
  11. Benchmark_InterfaceMapWithLockGet-4 10000000 149 ns/op 0 B/op 0 allocs/op
  12. Benchmark_InterfaceMapWithLockRemove-4 50000000 39.8 ns/op 0 B/op 0 allocs/op
  13. Benchmark_IntMapWithLockWithLockSet-4 5000000 304 ns/op 53 B/op 0 allocs/op
  14. Benchmark_IntMapWithLockGet-4 20000000 164 ns/op 0 B/op 0 allocs/op
  15. Benchmark_IntMapWithLockRemove-4 50000000 33.1 ns/op 0 B/op 0 allocs/op
  16. PASS
  17. ok command-line-arguments 47.503s