{"id":17335704,"url":"https://github.com/fufuok/cache","last_synced_at":"2025-04-14T17:30:54.575Z","repository":{"id":61625844,"uuid":"533341617","full_name":"fufuok/cache","owner":"fufuok","description":"🗃️ [高性能内存缓存库] Goroutine-safe, high-performance in-memory cache, optimized for reads over writes, with expiration, rich API, and support for generics.","archived":false,"fork":false,"pushed_at":"2024-07-18T05:44:39.000Z","size":230,"stargazers_count":11,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2024-11-01T05:42:24.054Z","etag":null,"topics":["go-cache"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/fufuok.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-09-06T13:39:28.000Z","updated_at":"2024-07-18T05:33:13.000Z","dependencies_parsed_at":"2024-07-18T07:20:49.386Z","dependency_job_id":"c004c2b8-eb76-45a3-b1ea-88801e4e2842","html_url":"https://github.com/fufuok/cache","commit_stats":null,"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fufuok%2Fcache","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fufuok%2Fcache/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fufuok%2Fcache/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fufuok%2Fcache/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fufuok","download_url":"https://codeload.github.com/fufuok/cache/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":223639403,"owners_count":17177816,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["go-cache"],"created_at":"2024-10-15T15:11:54.070Z","updated_at":"2024-11-08T06:03:13.849Z","avatar_url":"https://github.com/fufuok.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 🗃️ go-cache\n\nGoroutine-safe, high-performance in-memory cache, optimized for reads over writes, with expiration, rich API, and support for generics.\n\nBased on [puzpuzpuz/xsync](https://github.com/puzpuzpuz/xsync). thx.\n\nSee: [Benchmarks](#-benchmarks).\n\n## ⚙️ Installation\n\n```go\ngo get -u github.com/fufuok/cache\n```\n\n## ⚡️ Quickstart\n\n[DOC.md](DOC.md), Please see: [examples](examples)\n\n**Cache or CacheOf usage**\n\n```go\ntype Cache interface{ ... }\n    func New(opts ...Option) Cache\n    func NewDefault(defaultExpiration, cleanupInterval time.Duration, ...) Cache\ntype CacheOf[K comparable, V any] interface{ ... }\n    func NewOf[K comparable, V any](opts ...OptionOf[K, V]) CacheOf[K, V]\n    func NewOfDefault[K comparable, V any](defaultExpiration, cleanupInterval time.Duration, ...) CacheOf[K, V]\n\ntype Option func(config *Config)\n    func WithCleanupInterval(interval time.Duration) Option\n    func WithDefaultExpiration(duration time.Duration) Option\n    func WithEvictedCallback(ec EvictedCallback) Option\n    func WithMinCapacity(sizeHint int) Option\ntype OptionOf[K comparable, V any] func(config *ConfigOf[K, V])\n    func WithCleanupIntervalOf[K comparable, V any](interval time.Duration) OptionOf[K, V]\n    func WithDefaultExpirationOf[K comparable, V any](duration time.Duration) OptionOf[K, V]\n    func WithEvictedCallbackOf[K comparable, V any](ec EvictedCallbackOf[K, V]) OptionOf[K, V]\n    func WithMinCapacityOf[K comparable, V any](sizeHint int) OptionOf[K, V]\n```\n\n**Demo**\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/fufuok/cache\"\n)\n\nfunc main() {\n\t// for generics\n\t// c := cache.NewOf[string, int]()\n\tc := cache.New()\n\tc.SetForever(\"A\", 1)\n\tfmt.Println(c.GetOrSet(\"B\", 2, 1*time.Second)) // 2 false\n\ttime.Sleep(1 * time.Second)\n\tfmt.Println(c.Get(\"A\")) // 1, true\n\t// for generics\n\t// fmt.Println(c.Get(\"B\")) // 0, false\n\tfmt.Println(c.Get(\"B\")) // nil, false\n\tfmt.Println(c.Count())  // 1\n\tc.Clear()\n}\n```\n\n**Map or MapOf usage (similar to sync.Map)**\n\n```go\ntype Map interface{ ... }\n    func NewMap() Map\n    func NewMapPresized(sizeHint int) Map\ntype MapOf[K comparable, V any] interface{ ... }\n    func NewMapOf[K comparable, V any]() MapOf[K, V]\n    func NewMapOfPresized[K comparable, V any](sizeHint int) MapOf[K, V]\n```\n\n**Demo**\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/fufuok/cache\"\n)\n\nfunc main() {\n\t// for generics\n\t// m := cache.NewMapOf[string, int]()\n\tm := cache.NewMap()\n\tm.Store(\"A\", 1)\n\tfmt.Println(m.LoadOrStore(\"B\", 2)) // 2 false\n\tfmt.Println(m.LoadAndDelete(\"B\"))  // 2, true\n\tfmt.Println(m.Load(\"A\"))           // 1, true\n\t// for generics\n\t// fmt.Println(m.Load(\"B\")) // 0, false\n\tfmt.Println(m.Load(\"B\")) // nil, false\n\tfmt.Println(m.Size())    // 1\n\tm.Clear()\n}\n```\n\n## ✨ CacheOf Interface\n\n```go\ntype CacheOf[K comparable, V any] interface {\n\t// Set add item to the cache, replacing any existing items.\n\t// (DefaultExpiration), the item uses a cached default expiration time.\n\t// (NoExpiration), the item never expires.\n\t// All values less than or equal to 0 are the same except DefaultExpiration,\n\t// which means never expires.\n\tSet(k K, v V, d time.Duration)\n\n\t// SetDefault add item to the cache with the default expiration time,\n\t// replacing any existing items.\n\tSetDefault(k K, v V)\n\n\t// SetForever add item to cache and set to never expire, replacing any existing items.\n\tSetForever(k K, v V)\n\n\t// Get an item from the cache.\n\t// Returns the item or nil,\n\t// and a boolean indicating whether the key was found.\n\tGet(k K) (value V, ok bool)\n\n\t// GetWithExpiration get an item from the cache.\n\t// Returns the item or nil,\n\t// along with the expiration time, and a boolean indicating whether the key was found.\n\tGetWithExpiration(k K) (value V, expiration time.Time, ok bool)\n\n\t// GetWithTTL get an item from the cache.\n\t// Returns the item or nil,\n\t// with the remaining lifetime and a boolean indicating whether the key was found.\n\tGetWithTTL(k K) (value V, ttl time.Duration, ok bool)\n\n\t// GetOrSet returns the existing value for the key if present.\n\t// Otherwise, it stores and returns the given value.\n\t// The loaded result is true if the value was loaded, false if stored.\n\tGetOrSet(k K, v V, d time.Duration) (value V, loaded bool)\n\n\t// GetAndSet returns the existing value for the key if present,\n\t// while setting the new value for the key.\n\t// Otherwise, it stores and returns the given value.\n\t// The loaded result is true if the value was loaded, false otherwise.\n\tGetAndSet(k K, v V, d time.Duration) (value V, loaded bool)\n\n\t// GetAndRefresh Get an item from the cache, and refresh the item's expiration time.\n\t// Returns the item or nil,\n\t// and a boolean indicating whether the key was found.\n\tGetAndRefresh(k K, d time.Duration) (value V, loaded bool)\n\n\t// GetOrCompute returns the existing value for the key if present.\n\t// Otherwise, it computes the value using the provided function and\n\t// returns the computed value. The loaded result is true if the value\n\t// was loaded, false if stored.\n\tGetOrCompute(k K, valueFn func() V, d time.Duration) (V, bool)\n\n\t// Compute either sets the computed new value for the key or deletes\n\t// the value for the key. When the delete result of the valueFn function\n\t// is set to true, the value will be deleted, if it exists. When delete\n\t// is set to false, the value is updated to the newValue.\n\t// The ok result indicates whether value was computed and stored, thus, is\n\t// present in the map. The actual result contains the new value in cases where\n\t// the value was computed and stored. See the example for a few use cases.\n\tCompute(\n\t\tk K,\n\t\tvalueFn func(oldValue V, loaded bool) (newValue V, delete bool),\n\t\td time.Duration,\n\t) (V, bool)\n\n\t// GetAndDelete Get an item from the cache, and delete the key.\n\t// Returns the item or nil,\n\t// and a boolean indicating whether the key was found.\n\tGetAndDelete(k K) (value V, loaded bool)\n\n\t// Delete an item from the cache.\n\t// Does nothing if the key is not in the cache.\n\tDelete(k K)\n\n\t// DeleteExpired delete all expired items from the cache.\n\tDeleteExpired()\n\n\t// Range calls f sequentially for each key and value present in the map.\n\t// If f returns false, range stops the iteration.\n\tRange(f func(k K, v V) bool)\n\n\t// Items return the items in the cache.\n\t// This is a snapshot, which may include items that are about to expire.\n\tItems() map[K]V\n\n\t// Clear deletes all keys and values currently stored in the map.\n\tClear()\n\n\t// Count returns the number of items in the cache.\n\t// This may include items that have expired but have not been cleaned up.\n\tCount() int\n\n\t// DefaultExpiration returns the default expiration time for the cache.\n\tDefaultExpiration() time.Duration\n\n\t// SetDefaultExpiration sets the default expiration time for the cache.\n\t// Atomic safety.\n\tSetDefaultExpiration(defaultExpiration time.Duration)\n\n\t// EvictedCallback returns the callback function to execute\n\t// when a key-value pair expires and is evicted.\n\tEvictedCallback() EvictedCallbackOf[K, V]\n\n\t// SetEvictedCallback Set the callback function to be executed\n\t// when the key-value pair expires and is evicted.\n\t// Atomic safety.\n\tSetEvictedCallback(evictedCallback EvictedCallbackOf[K, V])\n}\n```\n\n## 🔰 MapOf Interface\n\n```go\ntype MapOf[K comparable, V any] interface {\n\t// Load returns the value stored in the map for a key, or nil if no\n\t// value is present.\n\t// The ok result indicates whether value was found in the map.\n\tLoad(key K) (value V, ok bool)\n\n\t// Store sets the value for a key.\n\tStore(key K, value V)\n\n\t// LoadOrStore returns the existing value for the key if present.\n\t// Otherwise, it stores and returns the given value.\n\t// The loaded result is true if the value was loaded, false if stored.\n\tLoadOrStore(key K, value V) (actual V, loaded bool)\n\n\t// LoadAndStore returns the existing value for the key if present,\n\t// while setting the new value for the key.\n\t// It stores the new value and returns the existing one, if present.\n\t// The loaded result is true if the existing value was loaded,\n\t// false otherwise.\n\tLoadAndStore(key K, value V) (actual V, loaded bool)\n\n\t// LoadOrCompute returns the existing value for the key if present.\n\t// Otherwise, it computes the value using the provided function and\n\t// returns the computed value. The loaded result is true if the value\n\t// was loaded, false if stored.\n\tLoadOrCompute(key K, valueFn func() V) (actual V, loaded bool)\n\n\t// Compute either sets the computed new value for the key or deletes\n\t// the value for the key. When the delete result of the valueFn function\n\t// is set to true, the value will be deleted, if it exists. When delete\n\t// is set to false, the value is updated to the newValue.\n\t// The ok result indicates whether value was computed and stored, thus, is\n\t// present in the map. The actual result contains the new value in cases where\n\t// the value was computed and stored. See the example for a few use cases.\n\tCompute(\n\t\tkey K,\n\t\tvalueFn func(oldValue V, loaded bool) (newValue V, delete bool),\n\t) (actual V, ok bool)\n\n\t// LoadAndDelete deletes the value for a key, returning the previous\n\t// value if any. The loaded result reports whether the key was\n\t// present.\n\tLoadAndDelete(key K) (value V, loaded bool)\n\n\t// Delete deletes the value for a key.\n\tDelete(key K)\n\n\t// Range calls f sequentially for each key and value present in the\n\t// map. If f returns false, range stops the iteration.\n\t//\n\t// Range does not necessarily correspond to any consistent snapshot\n\t// of the Map's contents: no key will be visited more than once, but\n\t// if the value for any key is stored or deleted concurrently, Range\n\t// may reflect any mapping for that key from any point during the\n\t// Range call.\n\t//\n\t// It is safe to modify the map while iterating it. However, the\n\t// concurrent modification rule apply, i.e. the changes may be not\n\t// reflected in the subsequently iterated entries.\n\tRange(f func(key K, value V) bool)\n\n\t// Clear deletes all keys and values currently stored in the map.\n\tClear()\n\n\t// Size returns current size of the map.\n\tSize() int\n}\n```\n\n## 🛠 ConfigOf\n\n```go\nconst (\n\t// NoExpiration mark cached item never expire.\n\tNoExpiration = -2 * time.Second\n\n\t// DefaultExpiration use the default expiration time set when the cache was created.\n\t// Equivalent to passing in the same e duration as was given to NewCache() or NewCacheDefault().\n\tDefaultExpiration = -1 * time.Second\n\n\t// DefaultCleanupInterval the default time interval for automatically cleaning up expired key-value pairs\n\tDefaultCleanupInterval = 10 * time.Second\n\n\t// DefaultMinCapacity specify the initial cache capacity (minimum capacity)\n\tDefaultMinCapacity = 32 * 3\n)\n\n// EvictedCallbackOf callback function to execute when the key-value pair expires and is evicted.\n// Warning: cannot block, it is recommended to use goroutine.\ntype EvictedCallbackOf[K comparable, V any] func(k K, v V)\n\ntype ConfigOf[K comparable, V any] struct {\n\t// DefaultExpiration default expiration time for key-value pairs.\n\tDefaultExpiration time.Duration\n\n\t// CleanupInterval the interval at which expired key-value pairs are automatically cleaned up.\n\tCleanupInterval time.Duration\n\n\t// EvictedCallback executed when the key-value pair expires.\n\tEvictedCallback EvictedCallbackOf[K, V]\n\n\t// MinCapacity specify the initial cache capacity (minimum capacity)\n\tMinCapacity int\n}\n```\n\n## 🤖 Benchmarks\n\n- Number of entries used in benchmark: `1_000_000`\n\n- ```go\n  {\"100%-reads\", 100}, // 100% loads,    0% stores,    0% deletes\n  {\"99%-reads\", 99},   //  99% loads,  0.5% stores,  0.5% deletes\n  {\"90%-reads\", 90},   //  90% loads,    5% stores,    5% deletes\n  {\"75%-reads\", 75},   //  75% loads, 12.5% stores, 12.5% deletes\n  {\"50%-reads\", 50},   //  50% loads,   25% stores,   25% deletes\n  {\"0%-reads\", 0},     //   0% loads,   50% stores,   50% deletes\n  ```\n\n```go\n# go test -run=^$ -benchtime=1s -bench=^BenchmarkCache\ngoos: linux\ngoarch: amd64\npkg: github.com/fufuok/cache\ncpu: AMD Ryzen 7 5700G with Radeon Graphics\nBenchmarkCache_NoWarmUp/99%-reads-16    63965202                17.95 ns/op\nBenchmarkCache_NoWarmUp/90%-reads-16    67328943                24.10 ns/op\nBenchmarkCache_NoWarmUp/75%-reads-16    58756623                23.86 ns/op\nBenchmarkCache_NoWarmUp/50%-reads-16    56851326                27.52 ns/op\nBenchmarkCache_NoWarmUp/0%-reads-16     48408231                30.44 ns/op\nBenchmarkCache_Integer_NoWarmUp/99%-reads-16            120131253               10.23 ns/op\nBenchmarkCache_Integer_NoWarmUp/90%-reads-16            100000000               13.78 ns/op\nBenchmarkCache_Integer_NoWarmUp/75%-reads-16            100000000               15.84 ns/op\nBenchmarkCache_Integer_NoWarmUp/50%-reads-16            100000000               17.66 ns/op\nBenchmarkCache_Integer_NoWarmUp/0%-reads-16             77839507                20.96 ns/op\nBenchmarkCache_WarmUp/100%-reads-16                     32617021                38.83 ns/op\nBenchmarkCache_WarmUp/99%-reads-16                      34722482                34.13 ns/op\nBenchmarkCache_WarmUp/90%-reads-16                      32676339                32.14 ns/op\nBenchmarkCache_WarmUp/75%-reads-16                      41837350                28.35 ns/op\nBenchmarkCache_WarmUp/50%-reads-16                      40624537                31.01 ns/op\nBenchmarkCache_WarmUp/0%-reads-16                       31336846                32.22 ns/op\nBenchmarkCache_Integer_WarmUp/100%-reads-16             67382474                18.11 ns/op\nBenchmarkCache_Integer_WarmUp/99%-reads-16              69214749                18.84 ns/op\nBenchmarkCache_Integer_WarmUp/90%-reads-16              71938634                16.10 ns/op\nBenchmarkCache_Integer_WarmUp/75%-reads-16              61299493                16.38 ns/op\nBenchmarkCache_Integer_WarmUp/50%-reads-16              58511590                18.37 ns/op\nBenchmarkCache_Integer_WarmUp/0%-reads-16               49336832                20.99 ns/op\nBenchmarkCache_Range-16                                      318           4516644 ns/op\n```\n\n```go\n# go test -run=^$ -benchtime=1s -bench=^BenchmarkMap\ngoos: linux\ngoarch: amd64\npkg: github.com/fufuok/cache\ncpu: AMD Ryzen 7 5700G with Radeon Graphics\nBenchmarkMap_NoWarmUp/99%-reads-16              72496048                18.52 ns/op\nBenchmarkMap_NoWarmUp/90%-reads-16              63024735                21.56 ns/op\nBenchmarkMap_NoWarmUp/75%-reads-16              59399750                25.12 ns/op\nBenchmarkMap_NoWarmUp/50%-reads-16              51399138                24.23 ns/op\nBenchmarkMap_NoWarmUp/0%-reads-16               51073983                28.00 ns/op\nBenchmarkMap_Integer_NoWarmUp/99%-reads-16              148085829                8.401 ns/op\nBenchmarkMap_Integer_NoWarmUp/90%-reads-16              100000000               12.25 ns/op\nBenchmarkMap_Integer_NoWarmUp/75%-reads-16              100000000               13.06 ns/op\nBenchmarkMap_Integer_NoWarmUp/50%-reads-16              100000000               14.64 ns/op\nBenchmarkMap_Integer_NoWarmUp/0%-reads-16               81655238                16.92 ns/op\nBenchmarkMap_StandardMap_NoWarmUp/99%-reads-16           5306242               319.2 ns/op\nBenchmarkMap_StandardMap_NoWarmUp/90%-reads-16           2906460               461.2 ns/op\nBenchmarkMap_StandardMap_NoWarmUp/75%-reads-16           2386760               504.1 ns/op\nBenchmarkMap_StandardMap_NoWarmUp/50%-reads-16           2469435               515.5 ns/op\nBenchmarkMap_StandardMap_NoWarmUp/0%-reads-16            1997181               575.5 ns/op\nBenchmarkMap_WarmUp/100%-reads-16                       37755207                31.90 ns/op\nBenchmarkMap_WarmUp/99%-reads-16                        36679430                31.53 ns/op\nBenchmarkMap_WarmUp/90%-reads-16                        45285555                26.23 ns/op\nBenchmarkMap_WarmUp/75%-reads-16                        45376821                25.98 ns/op\nBenchmarkMap_WarmUp/50%-reads-16                        35553566                28.31 ns/op\nBenchmarkMap_WarmUp/0%-reads-16                         33345013                34.30 ns/op\nBenchmarkMap_Integer_WarmUp/100%-reads-16               420121954                2.787 ns/op\nBenchmarkMap_Integer_WarmUp/99%-reads-16                161534372                7.975 ns/op\nBenchmarkMap_Integer_WarmUp/90%-reads-16                100000000               14.23 ns/op\nBenchmarkMap_Integer_WarmUp/75%-reads-16                80478811                15.98 ns/op\nBenchmarkMap_Integer_WarmUp/50%-reads-16                67574710                17.81 ns/op\nBenchmarkMap_Integer_WarmUp/0%-reads-16                 57477188                22.04 ns/op\nBenchmarkMap_StandardMap_WarmUp/100%-reads-16           13763970                77.03 ns/op\nBenchmarkMap_StandardMap_WarmUp/99%-reads-16             4539453               242.3 ns/op\nBenchmarkMap_StandardMap_WarmUp/90%-reads-16             4369597               240.1 ns/op\nBenchmarkMap_StandardMap_WarmUp/75%-reads-16             2665832               380.1 ns/op\nBenchmarkMap_StandardMap_WarmUp/50%-reads-16             2142928               500.8 ns/op\nBenchmarkMap_StandardMap_WarmUp/0%-reads-16              2104003               599.6 ns/op\nBenchmarkMap_Range-16                                        392           3183282 ns/op\nBenchmarkMap_RangeStandardMap-16                             188           6469273 ns/op\n```\n\n\n\n\n\n\n\n*ff*\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffufuok%2Fcache","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffufuok%2Fcache","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffufuok%2Fcache/lists"}