Go并发同步核心库syn包的使用深度指南

 更新时间:2026年03月20日 09:15:34   作者:程序员爱钓鱼  
在 Go 语言中,并发是最重要的特性之一,sync 是 Go 标准库中用于 并发控制与同步 的核心工具,下面小编就和大家详细介绍一下它的具体使用吧

在 Go 语言中,并发是最重要的特性之一。通过 goroutine 可以轻松启动成千上万个并发任务,但随之而来的问题是:如何安全地共享数据、控制执行顺序以及避免竞态条件。这正是 sync 包存在的意义。

sync 是 Go 标准库中用于 并发控制与同步 的核心工具,它提供了一系列原语(primitives),用于协调多个 goroutine 之间的执行关系。常见组件包括:MutexRWMutexWaitGroupOnceCondPool 等。

相比 channel,sync 更适合处理共享内存并发模型,尤其是在需要高性能或细粒度控制时。

互斥锁:sync.Mutex

最基础的同步工具是 Mutex(互斥锁),用于保证同一时间只有一个 goroutine 可以访问共享资源。

package main

import (
	"fmt"
	"sync"
)

var (
	count int
	mu    sync.Mutex
)

func add() {
	mu.Lock()
	count++
	mu.Unlock()
}

func main() {

	for i := 0; i < 1000; i++ {
		go add()
	}

	// 简单等待(真实项目应使用 WaitGroup)
	fmt.Scanln()

	fmt.Println(count)
}

如果没有加锁,多个 goroutine 同时修改 count,会导致数据错误(竞态条件)。加锁后可以保证数据安全。

需要注意的是:

  • Lock()Unlock() 必须成对出现
  • 通常推荐使用 defer mu.Unlock() 防止遗漏

读写锁:sync.RWMutex

当读操作远多于写操作时,可以使用读写锁优化性能。

var rw sync.RWMutex

// 读
rw.RLock()
value := count
rw.RUnlock()

// 写
rw.Lock()
count++
rw.Unlock()

特点:

  • 多个读可以并发执行
  • 写操作是独占的

适用于:

  • 缓存系统
  • 配置读取
  • 高读低写场景

等待组:sync.WaitGroup

WaitGroup 用于等待一组 goroutine 执行完成,是并发编程中最常用的工具之一。

package main

import (
	"fmt"
	"sync"
)

func worker(id int, wg *sync.WaitGroup) {
	defer wg.Done()
	fmt.Println("worker", id)
}

func main() {

	var wg sync.WaitGroup

	for i := 0; i < 5; i++ {
		wg.Add(1)
		go worker(i, &wg)
	}

	wg.Wait()

	fmt.Println("all done")
}

执行流程:

  • Add(n) 设置任务数量
  • 每个 goroutine 完成后调用 Done()
  • Wait() 阻塞直到所有任务完成

这是 Go 中控制并发任务结束的标准方式。

只执行一次:sync.Once

Once 用于保证某段代码只执行一次,常用于初始化操作。

var once sync.Once

func initConfig() {
	fmt.Println("初始化配置")
}

func main() {

	for i := 0; i < 3; i++ {
		go once.Do(initConfig)
	}

	fmt.Scanln()
}

无论调用多少次 Do(),函数只会执行一次。

适用于:

  • 单例模式
  • 配置加载
  • 资源初始化

条件变量:sync.Cond

Cond 用于在 goroutine 之间进行条件通知,类似“等待-唤醒”机制。

var mu sync.Mutex
cond := sync.NewCond(&mu)

ready := false

go func() {
	cond.L.Lock()
	for !ready {
		cond.Wait()
	}
	fmt.Println("开始执行")
	cond.L.Unlock()
}()

// 模拟准备完成
cond.L.Lock()
ready = true
cond.Signal()
cond.L.Unlock()

常见方法:

Wait()    等待条件
Signal()  唤醒一个
Broadcast() 唤醒所有

适用于:

  • 生产者消费者模型
  • 任务调度系统

对象池:sync.Pool

sync.Pool 用于缓存临时对象,减少内存分配,提高性能。

var pool = sync.Pool{
	New: func() interface{} {
		return make([]byte, 1024)
	},
}

func main() {

	buf := pool.Get().([]byte)

	// 使用 buf

	pool.Put(buf)
}

特点:

  • 自动回收(受 GC 管理)
  • 减少频繁分配内存

适用于:

  • 高频创建销毁对象
  • 日志系统
  • 序列化处理

Map 并发安全:sync.Map

Go 原生 map 不是并发安全的,sync.Map 提供了并发安全的 map。

var m sync.Map

m.Store("key", "value")

v, ok := m.Load("key")

fmt.Println(v, ok)

常用方法:

Store
Load
Delete
Range

适用于:

  • 读多写少场景
  • 缓存系统

sync 与 channel 对比

Go 并发有两种主流方式:

channel sync

对比:

方式特点
channel通信优先
sync共享内存控制

简单理解:

  • channel:通过通信共享数据
  • sync:通过共享内存同步数据

实际开发中,两者通常结合使用。

常见使用场景

在实际项目中,sync 广泛应用于:

  • 并发计数器(Mutex)
  • 任务调度(WaitGroup)
  • 单例初始化(Once)
  • 缓存系统(RWMutex / sync.Map)
  • 高性能对象复用(Pool)

例如实现一个并发安全计数器:

type Counter struct {
	mu sync.Mutex
	n  int
}

func (c *Counter) Add() {
	c.mu.Lock()
	defer c.mu.Unlock()
	c.n++
}

常见错误

忘记 Unlock:

mu.Lock()
// 没有 Unlock

导致死锁。

WaitGroup 使用错误:

wg.Add(1)
wg.Wait()
go func() {
	wg.Done()
}()

可能 panic。

复制 sync 对象:

mu2 := mu // 错误

sync 类型不能复制。

使用建议

实际开发中推荐:

  • 简单同步用 Mutex
  • 读多写少用 RWMutex
  • 等待任务用 WaitGroup
  • 初始化用 Once
  • 高性能缓存用 Pool
  • 并发 map 用 sync.Map

同时注意:

  • 尽量避免锁粒度过大
  • 避免死锁
  • 合理设计并发结构

总结

sync 是 Go 并发编程的核心工具库,它提供了一整套用于 协调 goroutine、保护共享数据、控制执行顺序 的机制。

核心组件包括:

  • Mutex / RWMutex:数据安全
  • WaitGroup:任务同步
  • Once:单次执行
  • Cond:条件通知
  • Pool:性能优化
  • sync.Map:并发 map

在高并发系统、Web 服务、任务调度器、缓存系统等场景中,sync 都是不可或缺的基础工具。熟练掌握 sync,可以让你的 Go 程序在并发安全和性能方面达到更高水平。

以上就是Go并发同步核心库syn包的使用深度指南的详细内容,更多关于Go syn并发同步的资料请关注脚本之家其它相关文章!

相关文章

  • Go语言每天必学之switch语句

    Go语言每天必学之switch语句

    这篇文章主要为大家详细介绍了Go语言每天必学之switch语句的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-12-12
  • golang线程安全的map实现

    golang线程安全的map实现

    这篇文章主要介绍了golang线程安全的map实现,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2019-03-03
  • 从Node.js 转到 Go平台

    从Node.js 转到 Go平台

    回顾过去的一年,我们在技术栈上的最大改变就是从 Node.js 切换到 Go 。我们的联合创始人,Steve Kaliski, 在 Poptip 把 Node.js 切换成了 Go,可惜他没有学习到当时的教训。
    2015-03-03
  • Go 简单实现多租户数据库隔离

    Go 简单实现多租户数据库隔离

    本文主要介绍了Go 简单实现多租户数据库隔离,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-05-05
  • Goland 的安装及激活教程(window、linux下安装)

    Goland 的安装及激活教程(window、linux下安装)

    这篇文章主要介绍了Golang Goland 的安装及激活详细教程,包括window下安装goland和linux下安装goland,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-10-10
  • Gin中数据解析和绑定的几种方法实现

    Gin中数据解析和绑定的几种方法实现

    本文主要介绍了Gin中数据解析和绑定的几种方法实现,包括Json数据、表单数据和URI数据,每种类型的数据都有其特定的解析和绑定方法,下面就一起来了解一下
    2025-11-11
  • Golang中常见加密算法的总结

    Golang中常见加密算法的总结

    这篇文章主要为大家详细介绍了Golang中常见的一些加密算法的实现,文中的示例代码讲解详细,具有一定的学习价值,感兴趣的小伙伴可以了解一下
    2023-03-03
  • Golang HashMap实现原理解析

    Golang HashMap实现原理解析

    HashMap是一种基于哈希表实现的键值对存储结构,它通过哈希函数将键映射到数组的索引位置,支持高效的插入、查找和删除操作,这篇文章主要介绍了Golang HashMap实现原理,需要的朋友可以参考下
    2025-04-04
  • Go语言kylin任务自动化实例详解

    Go语言kylin任务自动化实例详解

    这篇文章主要为大家介绍了Go语言kylin任务自动化实例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-06-06
  • Go中sync.Once源码的深度讲解

    Go中sync.Once源码的深度讲解

    sync.Once是Go语言标准库中的一个同步原语,用于确保某个操作只执行一次,本文将从源码出发为大家详细介绍一下sync.Once的具体使用,x希望对大家有所帮助
    2025-01-01

最新评论