mirror of
https://github.com/navidrome/navidrome.git
synced 2025-04-05 05:27:37 +03:00
Optimize Singleton (sometimes a simple lock is a better solution)
This commit is contained in:
parent
e50382e3bf
commit
0d8f8e3afd
2 changed files with 36 additions and 43 deletions
|
@ -3,49 +3,42 @@ package singleton
|
|||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"sync"
|
||||
|
||||
"github.com/navidrome/navidrome/log"
|
||||
)
|
||||
|
||||
var (
|
||||
instances = make(map[string]any)
|
||||
getOrCreateC = make(chan entry)
|
||||
instances = make(map[string]any)
|
||||
lock sync.RWMutex
|
||||
)
|
||||
|
||||
type entry struct {
|
||||
f func() any
|
||||
object any
|
||||
resultC chan any
|
||||
}
|
||||
|
||||
// GetInstance returns an existing instance of object. If it is not yet created, calls `constructor`, stores the
|
||||
// result for future calls and return it
|
||||
func GetInstance[T any](constructor func() T) T {
|
||||
var t T
|
||||
e := entry{
|
||||
object: t,
|
||||
f: func() any {
|
||||
return constructor()
|
||||
},
|
||||
resultC: make(chan any),
|
||||
}
|
||||
getOrCreateC <- e
|
||||
v := <-e.resultC
|
||||
return v.(T)
|
||||
}
|
||||
var v T
|
||||
name := reflect.TypeOf(v).String()
|
||||
|
||||
func init() {
|
||||
go func() {
|
||||
for {
|
||||
e := <-getOrCreateC
|
||||
name := reflect.TypeOf(e.object).String()
|
||||
v, created := instances[name]
|
||||
if !created {
|
||||
v = e.f()
|
||||
log.Trace("Created new singleton", "type", name, "instance", fmt.Sprintf("%+v", v))
|
||||
instances[name] = v
|
||||
}
|
||||
e.resultC <- v
|
||||
}
|
||||
v, available := func() (T, bool) {
|
||||
lock.RLock()
|
||||
defer lock.RUnlock()
|
||||
v, available := instances[name].(T)
|
||||
return v, available
|
||||
}()
|
||||
|
||||
if available {
|
||||
return v
|
||||
}
|
||||
|
||||
lock.Lock()
|
||||
defer lock.Unlock()
|
||||
v, available = instances[name].(T)
|
||||
if available {
|
||||
return v
|
||||
}
|
||||
|
||||
v = constructor()
|
||||
log.Trace("Created new singleton", "type", name, "instance", fmt.Sprintf("%+v", v))
|
||||
instances[name] = v
|
||||
return v
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue