singleflight

使用场景

在单体服务中的某一时间段的Cache Miss,造成大量的请求穿透Cache,打到DB上的场景。
使用单飞可以让一个请求去进行SELECT DB AND SET CACHE 操作,完成操作后让其它请求使用相同的结果进行返回

简单使用

安装库

go get golang.org/x/sync/singleflight

demo

package main

import (
	"fmt"
	"golang.org/x/sync/singleflight"
	"sync"
	"sync/atomic"
	"time"
)

var count int64

func main() {
	var group singleflight.Group
	g := sync.WaitGroup{}
	i := 0
	for i < 1000 {
		g.Add(1)
		i++
		go func() {
			r, _, _ := group.Do("abc", func() (interface{}, error) {
				time.Sleep(2 * time.Second)
				return getResult(), nil
			})
			fmt.Println(r) //ok
			g.Done()
		}()
	}
	g.Wait()
	fmt.Println(count) //1
}

func getResult() string {
	atomic.AddInt64(&count, 1)
	return "ok"
}

实现原理

这里仿照Do方法写的,少了一些error的处理
主要是用 sync.WaitGroup(add,wait,done)方法来实现

package main

import (
	"sync"
)

type rui struct {
	mu sync.Mutex
	m  map[string]*call
}

type ra struct {
	wg  sync.WaitGroup
	val interface{}
	err error
}

func (receiver *rui) Do(key string, fn func() (interface{}, error)) (interface{}, error) {
	receiver.mu.Lock()
	if receiver.m == nil {
		receiver.m = make(map[string]*call)
	}
	if c, ok := receiver.m[key]; ok {
		receiver.mu.Unlock()
		c.wg.Wait()
		return c.val, c.err
	}
	c := new(call)
	c.wg.Add(1)
	receiver.m[key] = c
	receiver.mu.Unlock()
	c.val, c.err = fn()
	defer c.wg.Done()
	return c.val, c.err
}

执行下自己写的单飞

package main

import (
	"fmt"
	"sync"
	"time"
)

func main() {
	group := rui{}
	g := sync.WaitGroup{}
	i := 0
	for i < 100 {
		g.Add(1)
		i++
		go func() {
			r, _ := group.Do("k", func() (interface{}, error) {
				time.Sleep(2 * time.Second)
				return "md", nil
			})
			fmt.Println(r)
			g.Done()
		}()
	}
	g.Wait()
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值