WaitGroup使用大家都会,但是其中是怎么实现的我们也需要知道,这样才能在项目中尽可能的避免由于不正确的使用引发的panic。并且本文也将写一下内存对齐方面做一个解析,喜欢大家喜欢。 WaitGroup介绍 WaitGroup 提供了三个方法: func (wg *WaitGroup) Add(delta int) func (wg *WaitGroup) Done() func (wg *WaitGroup) Wait() Add,用来设置 WaitGroup 的计数值; Done,用来将 WaitGroup 的计数值减 1,其实就是调用了 Add(-1); Wait,调用这个方法的 goroutine 会一直阻塞,直到 WaitGroup 的计数值变为 0。 例子我就不举了,网上是很多的,下面我们直接进入正题。 解析 type noCopy struct{} type WaitGroup struct { // 避免复制使用的一个技巧,可以告诉vet工具违反了复制使用的规则 noCopy noCopy // 一个复合值,用来表示waiter数、计数值、信号量 state1 [3]uint32 }// 获取state的地址和信号量的地址func (wg *WaitGroup) state() (statep *uint64, semap *uint32) { if uintptr(unsafe.Pointer(&wg.state1))%8 == 0 { // 如果地址是64bit对齐的,数组前两个元素做state,后一个元素做信号量 return (*uint64)(unsafe.Pointer(&wg.state1)), &wg.state1[2] } else { // 如果地址是 友链交易 32bit对齐的,数组后两个元素用来做state,它可以用来做64bit的原子操作,第一个元素32bit用来做信号量 return (*uint64)(unsafe.Pointer(&wg.state1[1])), &wg.state1[0] } } 这里刚开始,WaitGroup就秀了一把肌肉,让我们看看大牛是怎么写代码的,思考一个原子操作在不同架构平台上是怎么操作的,在看state方法里面为什么要这么做之前,我们先来看看内存对齐。 内存对齐 A memory address a is said to be n-byte aligned when a is a multiple of n (where n is a power of 2). 简而言之,现在的CPU访问内存的时候是一次性访问多个bytes,比如32位架构一次访问4bytes,该处理器只能从地址为4的倍数的内存开始读取数据,所以要求数据在存放的时候首地址的值是4的倍数存放,者就是所谓的内存对齐。 由于找不到Go语言的对齐规则,我对照了一下C语言的内存对齐的规则,可以和Go语言匹配的上,所以先参照下面的规则。 内存对齐遵循下面三个原则: 结构体变量的起始地址能够被其最宽的成员大小整除; 结构体每个成员相对于起始地址的偏移能够被其自身大小整除,如果不能则在前一个成员后面补充字节; 结构体总体大小能够被最宽的成员的大小整除,如不能则在后面补充字节; 通过下面的例子来实操一下内存对齐: 在32位架构中,int8占1byte,int32占4bytes,int16占2bytes。 type A struct { a int8 b int32 c int16 } type B struct { a int8 c int16 b int32 } func main() { fmt.Printf("arrange fields to reduce size:\n"+ "A align: %d, size: %d\n" , unsafe.Alignof(A{}), unsafe.Sizeof(A{}) ) fmt.Printf("arrange fields to reduce size:\n"+ "B align: %d, size: %d\n" , unsafe.Alignof(B{}), unsafe.Sizeof(B{}) ) } //output://arrange fields to reduce size://A align: 4, size: 12//arrange fields to reduce size://B align: 4, size: 8 下面以在32位的架构中运行为例子: 在32位架构的系统中默认的对齐大小是4bytes。 假设结构体A中a的起始地址为0x0000,能够被最宽的数据成员大小4bytes(int32)整除,所以从0x0000开始存放占用一个字节即0x00000x0001;b是int32,占4bytes,所以要满足条件2,需要在a后面padding3个byte,从0x0004开始;c是int16,占2bytes故从0x0008开始占用两个字节,即0x00080x0009;此时整个结构体占用的空间是0x0000~0x0009占用10个字节,10%4 != 0, 不满足第三个原则,所以需要在后面补充两个字节,即最后内存对齐后占用的空间是0x0000~0x000B,一共12个字节。
Go中由WaitGroup引发对内存对齐思考
来源:这里教程网
时间:2026-03-03 16:23:09
作者:
编辑推荐:
- Go中由WaitGroup引发对内存对齐思考03-03
- 【BUILD_ORACLE】使用ASMLib包搭建ASM磁盘03-03
- 还不知道简历如何写?就该这样写!03-03
- 你说那 class 文件里边都是啥03-03
- 降低代码的圈复杂度——复杂代码的解决之道03-03
- 降低代码的圈复杂度——复杂代码的解决之道03-03
- 你说那 class 文件里边都是啥03-03
- PLSQL Developer配置使用03-03
下一篇:
相关推荐
-
雷神推出 MIX PRO II 迷你主机:基于 Ultra 200H,玻璃上盖 + ARGB 灯效
2 月 9 日消息,雷神 (THUNDEROBOT) 现已宣布推出基于英
-
制造商 Musnap 推出彩色墨水屏电纸书 Ocean C:支持手写笔、第三方安卓应用
2 月 10 日消息,制造商 Musnap 现已在海外推出一款 Oce
热文推荐
- 【BUILD_ORACLE】使用ASMLib包搭建ASM磁盘
【BUILD_ORACLE】使用ASMLib包搭建ASM磁盘
26-03-03 - 干货 | 设计师必备中国风配色卡,快来收藏
干货 | 设计师必备中国风配色卡,快来收藏
26-03-03 - Thread 1 cannot allocate new log
Thread 1 cannot allocate new log
26-03-03 - Oracle database 19c中获取当前数据库版本的方法
Oracle database 19c中获取当前数据库版本的方法
26-03-03 - Oracle如何删除表中重复记录保留第一条
Oracle如何删除表中重复记录保留第一条
26-03-03 - Oracle网络服务基础(二)之监听器与TNS配置管理
Oracle网络服务基础(二)之监听器与TNS配置管理
26-03-03 - ORACLE 数据库业务用户密码重置慎用特殊字符
ORACLE 数据库业务用户密码重置慎用特殊字符
26-03-03 - oracle优化之生产系统不改代码解决SQL性能问题的几种方法
oracle优化之生产系统不改代码解决SQL性能问题的几种方法
26-03-03 - Oracle网络服务基础(一)之监听器概念
Oracle网络服务基础(一)之监听器概念
26-03-03 - Oracle 21c新特性预览与日常管理相关的几个新特性
Oracle 21c新特性预览与日常管理相关的几个新特性
26-03-03
