首页 > 编程语言 >go-zero 源码——syncx/singleflight

go-zero 源码——syncx/singleflight

时间:2023-07-04 12:13:10浏览次数:39  
标签:func val calls zero 源码 call key error go

package syncx

import "sync"

/**
 * [rtfsc]
 * 主题: singleflight.go
 * 摘要: 相同的任务,只需要一个人执行完成,剩下的享受成果即可
 * 功能: 多个协程执行同一个任务时,只需要一个执行成功,其余的共享结果即可
 * 应用: 高并发查询某个缓存未命中的记录,则只需允许一个协程去 db 查询即可,再将结果存到缓存,其余的直接获取缓存即可
 * [end]
 */

type (
	// SingleFlight lets the concurrent calls with the same key to share the call result.
	// For example, A called F, before it's done, B called F. Then B would not execute F,
	// and shared the result returned by F which called by A.
	// The calls with the same key are dependent, concurrent calls share the returned values.
	// A ------->calls F with key<------------------->returns val
	// B --------------------->calls F with key------>returns val
	SingleFlight interface {
		Do(key string, fn func() (any, error)) (any, error)
		DoEx(key string, fn func() (any, error)) (any, bool, error)
	}

	// [rtfsc]
	// 表示一次任务
	// wg  用于等待任务执行结束
	// val 任务执行的返回值
	// err 任务执行的错误
	// [end]
	call struct {
		wg  sync.WaitGroup
		val any
		err error
	}

	// [rtfsc]
	// 管理所有任务
	// calls 按 key 存放任务。实际上只存放一个执行中的任务,其他相同 key 的任务进来后,会直接返回已经存在的任务的引用
	// lock  用于在增减任务时加锁,毕竟 map 不是并发安全的
	// [end]
	flightGroup struct {
		calls map[string]*call
		lock  sync.Mutex
	}
)

// NewSingleFlight returns a SingleFlight.
func NewSingleFlight() SingleFlight {
	return &flightGroup{
		calls: make(map[string]*call),
	}
}

// [rtfsc]
// 执行一个任务
// 返回任务执行的结果。结果来自于:
// 1. 首次触发,调用 fn 得到
// 2. 非首次触发,共享首次触发时的结果
// [end]
func (g *flightGroup) Do(key string, fn func() (any, error)) (any, error) {
	c, done := g.createCall(key)
	if done {
		return c.val, c.err
	}

	g.makeCall(c, key, fn)
	return c.val, c.err
}

// [rtfsc]
// 执行一个任务,同 Do
// 不同之处在于,会返回的结果是由本次触发得到的,还是由其他触发得到的 (fresh:新鲜的结果)
// [end]
func (g *flightGroup) DoEx(key string, fn func() (any, error)) (val any, fresh bool, err error) {
	c, done := g.createCall(key)
	if done {
		return c.val, false, c.err
	}

	g.makeCall(c, key, fn)
	return c.val, true, c.err
}

// [rtfsc]
// 创建或者获取一个已经存在的 call,返回其引用
// c    call 的引用
// done 本次 call 是否完成了任务。完成了,则可以直接取 c.val
//
// 过程:
// 1. 操作 map 时加锁
// 2. 看当前的 key 是否有 call 在执行,有则直接取出,并等待这个 call 执行结束后返回。这样,同一个 key 不管调用多少次,都会等待同一个 call 的返回结果
// 3. 没有,则创建一个 call,并加入 map
// [end]
func (g *flightGroup) createCall(key string) (c *call, done bool) {
	g.lock.Lock()
	if c, ok := g.calls[key]; ok {
		g.lock.Unlock()
		c.wg.Wait()
		return c, true
	}

	c = new(call)
	c.wg.Add(1)
	g.calls[key] = c
	g.lock.Unlock()

	return c, false
}

// [rtfsc]
// 实际执行 call, 执行完成后,删除 map 中的 call
// [end]
func (g *flightGroup) makeCall(c *call, key string, fn func() (any, error)) {
	defer func() {
		g.lock.Lock()
		delete(g.calls, key)
		g.lock.Unlock()
		c.wg.Done()
	}()

	c.val, c.err = fn()
}

标签:func,val,calls,zero,源码,call,key,error,go
From: https://www.cnblogs.com/xiawanxw/p/17525398.html

相关文章

  • Python Django 零基础从零到一部署服务,Hello Django!全文件夹目录和核心代码!
    在这篇文章中,我将手把手地教你如何从零开始部署一个使用Django框架的Python服务。无论你是一个刚开始接触开发的新手,还是一个有经验的开发者想要快速了解Django,这篇教程都会为你提供一条清晰的路径。我们将从环境搭建开始,一步一步地创建一个可以处理GET和POST请求的服务,让你能在实......
  • go-zero 源码——syncx/limit
    rtfsc:readthefuckingsourcecode以下为源码注释:packagesyncximport( "errors" "github.com/zeromicro/go-zero/core/lang")/***[rtfsc]*主题:limit.go*摘要:类似信号量*功能:用于控制数量,如并发数*[end]*///ErrLimitReturnindicatestha......
  • nacos-sdk-go/v2版本 提示客户端连接不上
    nacos-sdk-gov2报错提示客户端连接不上标签(空格分隔):nacos前言nacos版本:v2nacos-sdk-go版本:v2背景:使用nacos-sdk-go来获取配置,发现一直在找缓存目录的文件,但使用openapi可以获取到配置报错信息clientnotconnected,currentstatus:STARTING提示客户端连接失败???1999-0......
  • go语言接口
    接口定义接口interface,和Java类似,是一组行为规范的集合,就是定义一组未实现的函数声明。谁使用接口就是参照接口的方法定义实现它们。type接口名interface{方法1(参数列表1)返回值列表1方法2(参数列表2)返回值列表2...}接口命名习惯在接口名后面加上......
  • Python Django 零基础从零到一部署服务,Hello Django!全文件夹目录和核心代码!
    在这篇文章中,我将手把手地教你如何从零开始部署一个使用Django框架的Python服务。无论你是一个刚开始接触开发的新手,还是一个有经验的开发者想要快速了解Django,这篇教程都会为你提供一条清晰的路径。我们将从环境搭建开始,一步一步地创建一个可以处理GET和POST请求的服务,让你能在实......
  • 语音房源码搭建技术分享之降噪功能详解
     噪音是指人们感觉到不愉快或干扰的声音,它通常是由于各种来源产生的不规则、杂乱的声音信号,噪音在我们生活中有很多的来源,像是环境噪音、社会噪音等,如果长时间暴露在噪音环境中可能导致许多健康问题,包括听力受损、睡眠障碍、心理压力增加、集中注意力困难等,而我今天要分享的知识......
  • GGTalk 开源即时通讯系统源码剖析之:数据库设计
    自从《开源即时通讯GGTalk8.0发布,增加Linux客户端,支持在统信UOS、银河麒麟上运行!》一文在博客园发布后,有园友联系我QQ,说能不能整理个更系统更详细地介绍GGTalk源码的文章,现在博客中的介绍比较零散,对于初级程序员而言,面对GGTalk大量的源码,有点不知所措。想想也是如此,于是,我打算写......
  • go get -u failed 失败 报错
    panic:internalerror:can'tfindreasonforrequirementongithub.com/pkg/[email protected][running]:cmd/go/internal/modget.(*resolver).updateBuildList.func1({{0x140000ba378,0x15},{0x14000110996,0x6}})/usr/local/go/src/cmd/go/......
  • 【HZERO】定时任务
    ......
  • Golang起步篇
    一.安装Go语言开发环境1.Wondows下搭建Go开发环境(1).下载SDK工具包sdk下载地址为:https://go.dev/dl/(2).解压下载的压缩包,放到特定的目录下,我一般放在d:/programs下(路径不能有中文或者特殊符号如空格等)(3).配置环境变量步骤1:先打开环境变量配置的界面步骤2:配置......