问题描述:
如下的函数被并发调用时,如果有重复的URL(在一个routine中被多次访问或多个routine访问同一个url),会产生冗余的网络请求。请实现一个并发安全的缓存,以提高网络的利用效率和降低函数的执行时间。完成后你将熟悉互斥锁的使用。
func httpGetBody(url string)(interface{},error){
resp,err:=http.Get(url)
if err!=nil{
return nil,err
}
defer resp.Body.Close()
return ioutil.ReadAll(resp.Body)
}
要点:
注意多个routine同时访问同一个URL时只需要发出一个网络请求。
拓展:
代码实现1:
import (
"sync"
)
type result struct{
value interface{}
err error
}
type entry struct {
res result
ready chan struct{}
}
type Func func(key string)(interface{}, error)
func New(f Func) *Memo{
return &Memo{f: f, cache: make(map[string] *entry)}
}
type Memo struct{
f Func
mu sync.Mutex
cache map[string] *entry
}
func (memo *Memo) Get(key string)(value interface{}, err 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 {
memo.mu.Unlock()
<-e.ready
}
return e.res.value, e.res.err
}
代码实现2:
type result struct{
value interface{}
err error
}
type entry struct {
res result
ready chan struct{}
}
type Func func(key string)(interface{}, error)
type request struct{
key string
response chan <- result
}
func New(f Func) *Memo{
memo := &Memo{requests: make(chan request)}
go memo.server(f)
return memo
}
type Memo struct{
requests chan request
}
func (memo *Memo) Get(key string)(value interface{}, err error){
response := make(chan result)
memo.requests <- request{key, response}
res := <- response
return res.value, res.err
}
func (memo *Memo) Close(){ close(memo.requests)}
func (memo *Memo) server(f Func){
cache := make(map[string] *entry)
for req := range memo.requests{
e := cache[req.key]
if e == nil{
e = &entry{ready: make(chan struct{})}
cache[req.key] = e
go e.call(f, req.key)
}
go e.deliver(req.response)
}
}
func (e *entry) call(f Func, key string){
e.res.value, e.res.err = f(key)
close(e.ready)
}
func (e *entry) deliver(response chan <- result) {
<- e.ready
response <- e.res
}
网友评论