go-singleflight并发重用

  • 主要目的是确保在多个 goroutine 同时请求相同的操作时,该操作只被执行一次,并且所有请求该操作的goroutine都能获取到相同的结果。

1 结构

type Group struct {
    mu sync.Mutex       // protects m
    m  map[string]*call // lazily initialized
}

type call struct {
    wg sync.WaitGroup

    // These fields are written once before the WaitGroup is done
    // and are only read after the WaitGroup is done.
    val interface{}
    err error

    // These fields are read and written with the singleflight
    // mutex held before the WaitGroup is done, and are read but
    // not written after the WaitGroup is done.
    dups  int
    chans []chan<- Result
}

// Result holds the results of Do, so they can be passed
// on a channel.
type Result struct {
    Val    interface{}
    Err    error
    Shared bool
}
  1. 并发操作转同步操作:由g.mu独占锁控制;在调用中,Do()/DoChan()、doCall()会尝试获取该锁再继续执行后续流程。
  • Do()/DoChan():传入待执行的函数f(),将其注册到mapg.m中。
  • doCall():负责执行所传入的函数f(),并将结果存放在call中。
  1. A未调用doCall(),B获取到g.mu,避免重复调用:
  • 由g.m控制;B命中时,则等待A执行完毕,使用其结果;未命中时,则调用doCall()。
  • 调用doCall()时,f()执行完毕后,会注销g.m中对应的值;若A快速获取g.mu且执行完doCall(),则B将未命中。

2 过程

  1. 运行过程可以分为两个部分:
  • Do()/DoChan():①获取锁,注册过则释放锁、等待退出;未注册则注册信息到g.m,继续过程②;②释放锁,调用doCall()。
  • doCall():③获取锁,执行f();④释放锁,注销g.m中对应的信息。
  1. 分类讨论返回值的情况:
  • A过程①->A过程②->B过程①->A过程③->A过程④,shared值:A false,B true
    在这里插入图片描述
  • A执行很快,快速获取到了Do与doCall中的锁,A过程①->A过程②->A过程③->B过程①->A过程④->B过程②->B过程③->B过程④,shared值:A false,B false
    在这里插入图片描述
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值