golang系列之-sync.Mutex
Mutex(MUTualEx)-互斥锁是一种可以保证每次只有一个goroutine访问贡献资源的方法。这个资源可以是一段程序代码、一个整数、一个map、一个struct、一个channel或其他任何东西。通过观察Mutex的源代码实现,可以将Mutex看作是一个队列(FIFO/LIFO),具体看后面的详细描述
当前go版本:1.24
快速上手
1 | package main |
上述代码运行结果如下
1 | go run ./main.go |
Mutex(MUTualEx)-互斥锁是一种可以保证每次只有一个goroutine访问贡献资源的方法。这个资源可以是一段程序代码、一个整数、一个map、一个struct、一个channel或其他任何东西。通过观察Mutex的源代码实现,可以将Mutex看作是一个队列(FIFO/LIFO),具体看后面的详细描述
当前go版本:1.24
1 | package main |
上述代码运行结果如下
1 | go run ./main.go |
sync.Cond经常用在多个 goroutine 等待,一个 goroutine 通知(事件发生)的场景。如果是一个通知,一个等待,使用互斥锁或 channel 就能搞定了。底层实现基于信号量semaphore
当前go版本:1.24
以下展示一个sync.Cond的使用案例
1 | package main |
并发情况下,如果需要等待所有的goroutine完成任务,需要使用Waitgroup等待
当前go版本:1.24
先简单列举一个使用案例,了解Waitgroup的使用
1 | package main |
上述代码执行后,系统输出如下,可以看到系统等待5个goroutine完成任务后才退出
1 | go run ./main.go |
sync/atomic标准库包中提供的原子操作。原子操作是无锁的,直接通过CPU指令实现。
当你想要在多个goroutine中无锁访问一个变量时,就可以考虑使用atomic包提供的数据类型实现
当前go版本:1.24
以下是一个使用atomic.Uint64数据类型实现的计数器,它确保了多个goroutine按顺序正确更新数据
1 | package main |
sync.Pool-临时对象池,是golang一个很关键的数据结构,通过复用历史对象,缓解因频繁创建、删除对象而导致的内存分配压力、GC压力,在社区中被广泛使用,有如go-gin、kubernetes等
当前go版本:1.24
下面展示一个简单的使用示例,用于帮助用户快速上手
1 | package main |
如果要实现如Singleton、Lazy Initialization模式,那么你需要了解sync.Once,它可以用于保证如:只加载一次配置文件、只初始化一次数据库连接等,此外它还可以帮助实现更好的Plugin封装
当前go版本:1.24
以下代码展示了如何使用sync.Once实现singleton模式
1 | package main |
map/哈希表,是golang常用的数据结构之一,也充当set数据结构的存在,相对slice要复杂很多。从1.24开始,swiss table替代noswiss成为默认实现,swiss与noswiss区别在于,swiss使用开放地址法,noswiss使用拉链法
当前go版本:1.24
swiss map的开关放在文件
src/internal/buildcfg/exp.go
的函数ParseGOEXPERIMENT
中
todo:文章图片待补充
1 | // table-groups是二维数组,算上slot的话是三维 |
核心数据结构包括Map、table、groupsReference、groupReference,具体如下
1 | // src/internal/runtime/maps/map.go |
map/哈希表,是golang常用的数据结构之一,也充当set数据结构的存在,相对slice要复杂很多。从1.24开始,swiss table替代noswiss成为默认实现,swiss与noswiss区别在于,swiss使用开放地址法,noswiss使用拉链法
当前go版本:1.23
todo:文章图片待补充
1 | // |
map的数据结构如下所示
1 | // src/runtime/map.go |
上面数据结构中中比较关键的是
hmap
- header部份,var变量存储的也是这部份buckets
- 指向一片连续内存区域,bucket数组bmap
- bucket的具体实现,可以存储8个key/value对,尾部overflow是溢出bucket的指针slice/切片-动态数组,golang常用的数据结构之一,相对于数组,slice可以追加元素,在容量不足时自动扩容
当前go版本:1.24
todo:文章图片待补充
slice数据结构如下所示
1 | // src/runtime/slice.go |
其中
array
- 指向一片连续内存区域的第一个元素len
- 已有元素数量cap
- 可容纳元素总数量slice初始化方式有三种
1 | // len=3 cap=3 |
以Ubuntu 24.04
为例,安装nerdctl
以及containerd
1 | sudo apt update && sudo apt install -y uidmap |
由于懒人安装方式跟单独安装方式bin目录不一致,配置内容会有些许差异,放在下面章节各自介绍