Skip to content

Latest commit

 

History

History
70 lines (56 loc) · 1.07 KB

loader.md

File metadata and controls

70 lines (56 loc) · 1.07 KB

Thread-safe Lazy Loading

package main

import (
	"embed"
	"fmt"
	"path/filepath"
	"sync"
)

//go:embed data/*.txt
var data embed.FS

func main() {
	one, err := data.ReadFile("data/one.txt")
	if err != nil {
		panic(err)
	}

	two, err := data.ReadFile("data/two.txt")
	if err != nil {
		panic(err)
	}

	fmt.Println(string(one))
	fmt.Println(string(two))
	l := &Loader{data: make(map[string][]byte)}
	fmt.Println(string(l.Load("one")))
	fmt.Println(string(l.Load("one")))
}

type Loader struct {
	mu   sync.RWMutex
	data map[string][]byte
}

func (l *Loader) Load(name string) []byte {
	name = filepath.Join("data", name+".txt")

	l.mu.RLock()
	b, ok := l.data[name]
	l.mu.RUnlock()
	if ok {
		return b
	}

	// Run the heavy function.
	// This is done outside the lock to prevent holding the lock.
	b, err := data.ReadFile(name)
	if err != nil {
		panic(err)
	}

	// Start a lock to store the data.
	l.mu.Lock()
	// We also check if the data already exists before overwriting.
	if b, ok := l.data[name]; ok {
		l.mu.Unlock()
		return b
	}

	l.data[name] = b
	l.mu.Unlock()

	return b
}