From f64e02a719c6a4ee339bf2529ca4aec111226b83 Mon Sep 17 00:00:00 2001 From: hlccd <56643462+hlccd@users.noreply.github.com> Date: Tue, 28 Dec 2021 22:47:34 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E4=BA=86=E5=B8=83=E9=9A=86?= =?UTF-8?q?=E8=BF=87=E6=BB=A4=E5=99=A8=E5=92=8C=E4=BD=8D=E5=9B=BE=E4=B8=AD?= =?UTF-8?q?=E5=87=BA=E7=8E=B0=E7=9A=84=E7=94=B1=E4=BD=8D=E8=BF=90=E7=AE=97?= =?UTF-8?q?=E5=AF=BC=E8=87=B4=E7=9A=84=E6=BA=A2=E5=87=BA=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- goSTL/algorithm/singleFlight/singleFlight.go | 93 +++++++++++++------ goSTL/data_structure/bitmap/bitmap.go | 2 +- .../data_structure/bloomFilter/bloomFilter.go | 34 ++++--- 3 files changed, 87 insertions(+), 42 deletions(-) diff --git a/goSTL/algorithm/singleFlight/singleFlight.go b/goSTL/algorithm/singleFlight/singleFlight.go index 7a7315d..f186223 100644 --- a/goSTL/algorithm/singleFlight/singleFlight.go +++ b/goSTL/algorithm/singleFlight/singleFlight.go @@ -1,5 +1,15 @@ package singleFlight +//@Title singleFlight +//@Description +// 单次请求-single flight +// 利用可重入锁避免对于一个同类的请求进行多次从而导致的缓存击穿的问题 +// 缓存击穿: +// 缓存在某个时间点过期的时候 +// 恰好在这个时间点对这个Key有大量的并发请求过来 +// 这些请求发现缓存过期一般都会从后端DB加载数据并回设到缓存 +// 这个时候大并发的请求可能会瞬间把后端DB压垮。 + import "sync" //呼叫请求结构体 @@ -9,61 +19,88 @@ type call struct { err error //错误反馈 } +//一组请求工作 +//每一类请求对应一个call,利用其内部的可重入锁避免一类请求在短时间内频繁执行 +//请求组工作由使用者自行分配空间来实现 type Group struct { - mu sync.Mutex // protects m - m map[string]*call//所有请求 + m map[string]*call //一类请求与同一类呼叫的映射表 + mu sync.Mutex //并发控制锁,保证线程安全 } -//防止击穿缓存,对同一个key进行请求时需要分别进行,利用可重入锁实现 -func (g *Group) Do(key string, fn func() (interface{}, error)) (interface{}, error) { +//@title Do +//@description +// 以请求做做接收者 +// 传入一个请求类的key和请求调用函数fn +// 请求时候需要等待之前有的同类请求先完成在进行 +// 防止击穿缓存,对同一个key进行请求时需要分别进行,利用可重入锁实现 +// 请求完成后返回结果和错误信息即可 +//@receiver g *Group 接受者请求组的指针 +//@param key string 请求的关键词key +//@param fn func() (interface{}, error) 请求执行函数 +//@return v interface{} 请求执行得到的结果 +//@return err error 执行请求后的错误信息 +func (g *Group) Do(key string, fn func() (interface{}, error)) (v interface{}, err error) { g.mu.Lock() if g.m == nil { g.m = make(map[string]*call) } + //判断以key为关键词的该类请求是否存在 if c, ok := g.m[key]; ok { g.mu.Unlock() - c.wg.Wait() // 如果请求正在进行中,则等待 - return c.val, c.err // 请求结束,返回结果 + // 如果请求正在进行中,则等待 + c.wg.Wait() + return c.val, c.err } + //该类请求不存在,创建个请求 c := new(call) - c.wg.Add(1) // 发起请求前加锁 - g.m[key] = c // 添加到 g.m,表明 key 已经有对应的请求在处理 + // 发起请求前加锁,并将请求添加到请求组内以表示该类请求正在处理 + c.wg.Add(1) + g.m[key] = c g.mu.Unlock() - - c.val, c.err = fn() // 调用 fn,发起请求 - c.wg.Done() // 请求结束 - + //调用请求函数获取内容 + c.val, c.err = fn() + //请求结束 + c.wg.Done() g.mu.Lock() - delete(g.m, key) // 更新 g.m + //从请求组中删除该呼叫请求 + delete(g.m, key) g.mu.Unlock() - - return c.val, c.err // 返回结果 + return c.val, c.err } +//@title hash +//@description +// 以请求做做接收者 +// 传入一个请求类的key和请求调用函数fn +// 请求时候需要等待之前有的同类请求先完成在进行 +// 防止击穿缓存,对同一个key进行请求时需要分别进行,利用可重入锁实现 +// 返回一个channel,利用fn函数获取到的数据将会传入其中 +// 可利用channel做超时控制 +//@receiver g *Group 接受者请求组的指针 +//@param key string 请求的关键词key +//@param fn func() (interface{}, error) 请求执行函数 +//@return ch chan interface{} 执行结果将会传入其中,可做超时控制 func (g *Group) DoChan(key string, fn func() (interface{}, error)) (ch chan interface{}) { - ch = make(chan interface{}) + ch = make(chan interface{}, 1) g.mu.Lock() if g.m == nil { g.m = make(map[string]*call) } - if c, ok := g.m[key]; ok { + if _, ok := g.m[key]; ok { g.mu.Unlock() - c.wg.Wait() // 如果请求正在进行中,则等待 - ch <- c.val return ch } c := new(call) c.wg.Add(1) // 发起请求前加锁 g.m[key] = c // 添加到 g.m,表明 key 已经有对应的请求在处理 g.mu.Unlock() - - c.val, c.err = fn() // 调用 fn,发起请求 - c.wg.Done() // 请求结束 - ch <- c.val - - g.mu.Lock() - delete(g.m, key) // 更新 g.m - g.mu.Unlock() - + go func() { + c.val, c.err = fn() // 调用 fn,发起请求 + c.wg.Done() // 请求结束 + g.mu.Lock() + delete(g.m, key) // 更新 g.m + ch <- c.val + g.mu.Unlock() + }() return ch } diff --git a/goSTL/data_structure/bitmap/bitmap.go b/goSTL/data_structure/bitmap/bitmap.go index e687128..38d9e79 100644 --- a/goSTL/data_structure/bitmap/bitmap.go +++ b/goSTL/data_structure/bitmap/bitmap.go @@ -138,7 +138,7 @@ func (bm *Bitmap) Check(num uint) (b bool) { return false } //判断第num是否为1,为1返回true,否则为false - if bm.bits[num/64]&(1< 0 { + if bm.bits[num/64]&(1<<(num%64)) > 0 { return true } return false diff --git a/goSTL/data_structure/bloomFilter/bloomFilter.go b/goSTL/data_structure/bloomFilter/bloomFilter.go index 3ae58d7..ed0010f 100644 --- a/goSTL/data_structure/bloomFilter/bloomFilter.go +++ b/goSTL/data_structure/bloomFilter/bloomFilter.go @@ -15,6 +15,7 @@ import "fmt" //选用uint64是为了更多的利用bit位 type bloomFilter struct { bits []uint64 + hash Hash } //bloomFilter布隆过滤器接口 @@ -26,6 +27,9 @@ type bloomFilteror interface { Clear() //清空该布隆过滤器 } +//允许自行传入hash函数 +type Hash func(v interface{}) (h uint32) + //@title hash //@description // 传入一个虚拟节点id和实际结点 @@ -33,13 +37,13 @@ type bloomFilteror interface { // 逐层访问并利用素数131计算其hash值随后返回 //@receiver nil //@param v interface{} 待计算的值 -//@return h uint64 计算得到的hash值 -func hash(v interface{}) (h uint64) { - h = uint64(0) - s := fmt.Sprintf("v", v) +//@return h uint32 计算得到的hash值 +func hash(v interface{}) (h uint32) { + h = uint32(0) + s := fmt.Sprintf("131-%v-%v", v,v) bs := []byte(s) for i := range bs { - h += uint64(bs[i]) * 131 + h += uint32(bs[i]) * 131 } return h } @@ -49,11 +53,15 @@ func hash(v interface{}) (h uint64) { // 新建一个bloomFilter布隆过滤器容器并返回 // 初始bloomFilter的切片数组为空 //@receiver nil -//@param nil +//@param h Hash hash函数 //@return bf *bloomFilter 新建的bloomFilter指针 -func New() (bf *bloomFilter) { +func New(h Hash) (bf *bloomFilter) { + if h == nil { + h = hash + } return &bloomFilter{ bits: make([]uint64, 0, 0), + hash: h, } } @@ -74,12 +82,12 @@ func (bf *bloomFilter) Insert(v interface{}) { return } //开始插入 - h := hash(v) - if h/64+1 > uint64(len(bf.bits)) { + h := bf.hash(v) + if h/64+1 > uint32(len(bf.bits)) { //当前冗余量小于num位,需要扩增 var tmp []uint64 //通过冗余扩增减少扩增次数 - if h/64+1 < uint64(len(bf.bits)+1024) { + if h/64+1 < uint32(len(bf.bits)+1024) { //入的位比冗余的多不足2^16即1024*64时,则新增1024个uint64 tmp = make([]uint64, len(bf.bits)+1024) } else { @@ -110,13 +118,13 @@ func (bf *bloomFilter) Check(v interface{}) (b bool) { if bf == nil { return false } - h := hash(v) + h := bf.hash(v) //h超出范围,直接返回false并结束 - if h/64+1 > uint64(len(bf.bits)) { + if h/64+1 > uint32(len(bf.bits)) { return false } //判断第num是否为1,为1返回true,否则为false - if bf.bits[h/64]&(1< 0 { + if bf.bits[h/64]&(1<<(h%64)) > 0 { return true } return false