golang并发编程知识点总结

互斥锁:Mutex
package main import ( "fmt" "sync" ) func main() { var count = 0 var mux sync.Mutex var wg sync.WaitGroup wg.Add(10) for i := 0; i < 10; i++ { go func() { defer wg.Done() for i := 0; i < 10000; i++ { count = count + 1 } mux.Unlock() }() } wg.Wait() fmt.Printf("count=%d\n", count) }
package main import ( "fmt" "sync" "time" ) type Counter struct { mu sync.RWMutex count int64 } func (c *Counter) Incr() { c.mu.Lock() c.count = c.count + 1 c.mu.Unlock() } func (c *Counter) Get() int64 { c.mu.RLock() defer c.mu.RUnlock() return c.count } func main() { var counter = &Counter{} for i := 0; i < 10; i++ { // 10个reader go func() { for { counter.Get() // 计数器读操作 fmt.Printf("count=%d\n", counter.Get()) time.Sleep(time.Millisecond) } }() } for { // 一个writer counter.Incr() // 计数器写操作 time.Sleep(time.Second) } }
条件变量
package main import ( "log" "math/rand" "sync" "time" ) func main() { c := sync.NewCond(&sync.Mutex{}) var ready int for i := 0; i < 10; i++ { go func(i int) { time.Sleep(time.Duration(rand.Int63n(10)) * time.Second) c.L.Lock() ready++ c.L.Unlock() log.Printf("运动员#%d 已准备就绪", i) c.Broadcast() }(i) } c.L.Lock() for ready != 10 { c.Wait() log.Println("裁判员被唤醒一次") } c.L.Unlock() log.Println("所有运动员都准备就绪。比赛开始,3,2,1, ......") }
几种fork/join方式
package main import ( "context" "errors" "fmt" "github.com/go-pkgz/syncs" "github.com/mdlayher/schedgroup" "github.com/vardius/gollback" "golang.org/x/sync/errgroup" "log" "sync/atomic" "time" ) func main99() { var g = errgroup.Group{} for i := 0; i < 10; i++ { g.Go(func() error { time.Sleep(5 * time.Second) fmt.Println("exec #1") return nil }) } if err := g.Wait(); err == nil { fmt.Println("Successfully exec all") } else { fmt.Println("failed:", err) } } func main98() { // 设置goroutine数是10 swg := syncs.NewSizedGroup(10) // swg := syncs.NewSizedGroup(10, syncs.Preemptive) var c uint32 // 执行1000个子任务,只会有10个goroutine去执行 for i := 0; i < 1000; i++ { swg.Go(func(ctx context.Context) { time.Sleep(5 * time.Millisecond) atomic.AddUint32(&c, 1) }) } // 等待任务完成 swg.Wait() // 输出结果 fmt.Println(c) } func main97() { rs, errs := gollback.All( // 调用All方法 context.Background(), func(ctx context.Context) (interface{}, error) { time.Sleep(3 * time.Second) return 1, nil // 第一个任务没有错误,返回1 }, func(ctx context.Context) (interface{}, error) { return nil, errors.New("failed") // 第二个任务返回一个错误 }, func(ctx context.Context) (interface{}, error) { return 3, nil // 第三个任务没有错误,返回3 }, ) fmt.Println(rs) // 输出子任务的结果 fmt.Println(errs) // 输出子任务的错误信息 ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() res, err := gollback.Retry(ctx, 5, func(ctx context.Context) (interface{}, error) { log.Print("重试...") return nil, errors.New("failed") }) fmt.Println(res) // 输出结果 fmt.Println(err) // 输出错误信息 } func main() { sg := schedgroup.New(context.Background()) // 设置子任务分别在100、200、300之后执行 for i := 0; i < 3; i++ { n := i + 1 sg.Delay(time.Duration(n)*100*time.Millisecond, func() { log.Println(n) //输出任务编号 }) } // 等待所有的子任务都完成 if err := sg.Wait(); err != nil { log.Fatalf("failed to wait: %v", err) } }
信号量:Seamphore
package main import ( "context" "fmt" "golang.org/x/sync/semaphore" "log" "runtime" "time" ) var ( maxWorkers = runtime.GOMAXPROCS(0) // worker数量 sema = semaphore.NewWeighted(int64(maxWorkers)) //信号量 task = make([]int, maxWorkers*4) // 任务数,是worker的四倍 ) func main() { log.Printf("max workers:%d", maxWorkers) ctx := context.Background() max := len(task) * 2 for i := 0; i < max; i++ { // 如果没有worker可用,会阻塞在这里,直到某个worker被释放 if err := sema.Acquire(ctx, 1); err != nil { log.Printf("发生阻塞...") break } // 启动worker goroutine go func(i int) { defer sema.Release(1) time.Sleep(1000 * time.Millisecond) // 模拟一个耗时操作 task[i] = i + 1 fmt.Println("执行。。。") }(i) } // 请求所有的worker,这样能确保前面的worker都执行完 if err := sema.Acquire(ctx, int64(maxWorkers)); err != nil { log.Printf("获取所有的worker失败: %v", err) } fmt.Println(task) }
分类:
Golang / 并发编程
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix