sync.waitGroup的wait可以多次wait,同时通知
最近读groupcache的源码,有个一次执行的模块。
保证同一个key的函数只执行一次。
原理是利用sync.waitGroup的wait可以同步阻塞。然后等待所有的wait完成
写了个测试的demo程序,其实还是需要分析下标准库源码。
wait是个for循环,检测当前的状态
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | for { state := atomic.LoadUint64(statep) v := int32(state >> 32) w := uint32(state) if v == 0 { // Counter is 0, no need to wait. if race.Enabled { race.Enable() race.Acquire(unsafe.Pointer(wg)) } return } // Increment waiters count. if atomic.CompareAndSwapUint64(statep, state, state+1) { if race.Enabled && w == 0 { // Wait must be synchronized with the first Add. // Need to model this is as a write to race with the read in Add. // As a consequence, can do the write only for the first waiter, // otherwise concurrent Waits will race with each other. race.Write(unsafe.Pointer(semap)) } runtime_Semacquire(semap) if *statep != 0 { panic( "sync: WaitGroup is reused before previous Wait has returned" ) } if race.Enabled { race.Enable() race.Acquire(unsafe.Pointer(wg)) } return } } |
如下是我的demo

1 package main 2 3 import ( 4 "fmt" 5 "sync" 6 "time" 7 ) 8 9 10 /* 11 测试多个wait的情况 12 13 */ 14 func main() { 15 fmt.Println("start") 16 17 var group sync.WaitGroup 18 19 group.Add(1) 20 for i:=0; i< 10; i++{ 21 go func(i int){ 22 fmt.Printf("process %d waiting\n", i) 23 group.Wait() 24 fmt.Printf("process %d waiting done\n", i) 25 }(i) 26 } 27 time.Sleep(time.Second * 1) 28 group.Done() 29 30 time.Sleep(time.Second * 1) 31 32 fmt.Println("end") 33 }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律