美文网首页
golang练手小项目系列(5)-并发无阻塞缓存

golang练手小项目系列(5)-并发无阻塞缓存

作者: 李说的对 | 来源:发表于2019-06-28 19:21 被阅读0次

    问题描述:

    如下的函数被并发调用时,如果有重复的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

    }

    相关文章

      网友评论

          本文标题:golang练手小项目系列(5)-并发无阻塞缓存

          本文链接:https://www.haomeiwen.com/subject/iiaecctx.html