美文网首页
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)-并发无阻塞缓存

    问题描述: 如下的函数被并发调用时,如果有重复的URL(在一个routine中被多次访问或多个routine访问同...

  • golang练手小项目系列(2)-并发爬虫

    本系列整理了10个工作量和难度适中的Golang小项目,适合已经掌握Go语法的工程师进一步熟练语法和常用库的用法。...

  • Golang练手小项目系列

    本系列整理了10个工作量和难度适中的Golang小项目,适合已经掌握Go语法的工程师进一步熟练语法和常用库的用法。...

  • 计划

    1、新框架MVVM项目练手 2、本地数据缓存 3、自定义ViewGroup(手势、复杂) 4、hook技术 5、A...

  • Golang使用redis阻塞读brpop实现即时响应并发执行

    实现 主要利用redis的brpop阻塞读和Golang的goroutine并发控制以及os/exec执行程序,实...

  • golang练手小项目系列(3)-并发读取文件夹信息

    问题描述: 实现一个程序计算并打印输入的目录下所有文件的总数和总大小(以GB计算)。完成之后你将熟悉select、...

  • golang练手小项目系列(1)-位向量

    本系列整理了10个工作量和难度适中的Golang小项目,适合已经掌握Go语法的工程师进一步熟练语法和常用库的用法。...

  • golang之Struct

    最近在复习golang,学习的东西,如果不使用,很快就会忘记。所以,准备复习完golang,做一个练手的小项目,加...

  • 异步编程

    同步、异步、阻塞、非阻塞 Future JDK 5引入了Future模式。重点实现的是并发处理,异步阻塞 Futu...

  • 并发几个概念

    1.同步与异步 2.并发和并行 3.临界区 4.阻塞和非阻塞 5.死锁、饥饿、活锁 6.并发级别 6.1阻塞 6....

网友评论

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

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