golang——并发、重复抑制、非阻塞缓存
package main
import (
"fmt"
"io/ioutil"
"net/http"
"sync"
"time"
)
type entry struct {
res result
ready chan struct{} // 重复抑制
}
type result struct {
value interface{}
err error
}
type Memo struct {
f Func
mu sync.Mutex
cache map[string]*entry // 本地缓存
}
type Func func(key string) (interface{}, error)
func New(f Func) *Memo {
return &Memo{f: f, cache: make(map[string]*entry)}
}
func (memo *Memo) Get(key string) (interface{}, error) {
memo.mu.Lock()
e := memo.cache[key]
if e == nil {
e = &entry{ready: make(chan struct{})}
memo.cache[key] = e
memo.mu.Unlock()
e.res.value, e.res.err = memo.f(key)
close(e.ready)
} else {
fmt.Println(key)
memo.mu.Unlock()
<-e.ready
}
return e.res.value, e.res.err
}
func httpGetBody(url string) (interface{}, error) {
client := http.Client{Timeout: 1 * time.Second}
resp, err := client.Get(url)
if err != nil {
return nil, err
}
defer resp.Body.Close()
return ioutil.ReadAll(resp.Body)
}
func incomingURLs() []string {
return []string{
"https://blog.csdn.net/liyuxing6639801",
"https://zhuanlan.zhihu.com/p/95056679",
"https://blog.csdn.net/chenbaoke/article/details/42782767",
"https://www.jianshu.com/p/228c119a7d0e",
"https://github.com/disintegration/imaging",
"https://github.com/disintegration/imaging",
}
}
func main() {
m := New(httpGetBody)
n := sync.WaitGroup{}
for _, url := range incomingURLs() {
n.Add(1)
go func(url string) {
start := time.Now()
value, err := m.Get(url)
if err != nil {
fmt.Println(err)
n.Done()
return
}
fmt.Printf("%s, %s, %d bytes\n", url, time.Since(start), len(value.([]byte)))
n.Done()
}(url)
}
n.Wait()
}