Go 编程技巧
2022-01-24 17:53:58 2 举报
AI智能生成
Go 编程技巧,持续更新中。。。
作者其他创作
大纲/内容
Functional Options Pattern
Sort
性能分析工具
安装
流处理
类型
类型断言 t, ok := i.(T)
类型选择 switch val := a.(type) { }
类型转换 T(v)
字符编码
提问
一个 string 类型的值在底层怎样被表达的?
遍历字符串时,迭代变量下标不连续的问题?
如果字符串中出现中文字符不能直接调用 len 函数来统计字符串字符长度?
子主题
字符串拼接
字符串转字节数组
高阶函数
将函数做为参数
将函数作为返回值
数据集合
slice
优化底层存储的数组大小
你真的彻底理解切片结构了吗?
并发
并发思想
核心问题:保证一致性和正确性
let it crash
并发线程间的通信
共享数据
锁机制
消息传递
基于 channel
基于 Actor
并发原语
锁
作用:保护临界区/共享资源
分类
Mutex
RWMutex
检查数据竞争data race
条件变量 Cond
作用:当共享资源状态改变时,通知被互斥锁阻塞的线程;而当条件不满足时,线程不用重复检查等待通知即可;
使用
基于锁进行初始化
操作方法
wait - 等待通知
1. 将调用这个方法 goroutine 加入到当前变量的通知队列中
2. 解锁当前条件变量基于的那个互斥锁,因此在调用 wati( )前必须锁定那个互斥锁,否则会引发 panic
3. 让当前的 goroutine 处于等待状态,等待通知唤醒;此时会阻塞在 wait() 这行代码上。
4. 被通知唤醒后,决定唤醒 goroutine 时重新锁定这个条件变量基于的互斥锁
signal - 单发通知
broadcast - 广播通知
注意事项
为什么用for语句来包裹其wait()的表达式,用if语句不行吗?
条件变量的通知具有即时性
sync.Cond 不能被复制
与锁之前关系?必须基于锁才能发挥作用
常见用武之地:广播通知
消息传递 Channel
定义
常见语法
通道工厂模式
生产者消费者模式
管道和选择器模式
Futures模式
信号量模式
不返回结果
有返回结果
常见语句
使用_,ok判断channel是否关闭
使用for range读channel
使用 select 切换协程
使用channel的声明控制读写权限
使用close(ch)关闭所有下游协程
单个协程的退出
常见应用
结合计时器 Ticker,限制处理频率
结合定时器Timer,进行周期请求、操作加上超时检测
信号量
增强并发-并行化
惰性生成器
使用技巧
传递数据时 - 传递结构体的指针而非结构体
传递信号时 - 传递空struct
原子操作 sync/atomic
原子性执行&原子操作
提供几种原子操作
Store - 存储
Load -加载
Add - 加数
Swap - 交换
CompareAndSwap - 比较并交换
为什么操作函数入参都是指针类型?
可操作的数据类型有哪些?
int32/int64/uint32/uint64/uintptr
unsafe.Pointer - 没有提供add操作
AddUint32/AddUint64 操作可以做减法吗?可以
Value:存储任意类型的值
高级同步工具
单次执行 sync.Once
提问
是每一种参数函数都执行一次吗?
如何保障只执行参数函数一次的?如果执行时发生panic,会在再执行一次吗?
可能会产出死锁问题吗?如何避免?
内部实现
特点:双重检查,快慢路径结合
注意功能缺失:对 done 字段赋值用的是原子操作,并且该操作在 defer 语句中
注意阻塞:Do 方法只会在参数函数执行结束之后把 done 字段的值变为1
任务编排 sync.WaitGroup
提问
计数器的值可以小于 0 吗?
使用时导致 panic 的原因有几种?
内部实现:一个计数器
不要让计数器值小于0,否则会引发 panic
保证计数周期完整性,防止操作并发执行,否则可能会引发 panic
数据共享 context.Context
提问
“可撤销”代表着什么?撤销一个 Context 值意味着什么?撤销信号是如何在上下文树中传播的?
怎样通过 Context 值携带数据?如何从中获取数据?可以修改数据吗?
Context值在传达撤销信号的时候是广度优先的,还是深度优先的?
内部实现
按 Context 值划分
根 Context 值
Background()
TODO()
可撤销的 Context 值
只能手动撤销 - WithCancel
可以定时撤销 - WithTimeout、WithDeadline
含数据的 Context 值 - WithValue
撤销过程
Done():返回一个用于调用方感知“撤销信号”的通道
Err():感知到“撤销”的具体原因
含数据的 Context 值不能被撤销,而可撤销的 Context 值有无法携带数据就,信号递归按上下文树叶子节点的方向传播
实现一对多的协作流程:Channel VS WaitGroup VS Context
混合使用案例
golang.org/x/sync/errgroup
golang.org/x/sync/singleflight
临时对象池 sync.Pool
提问
如何定义临时对象?
存在意义:帮助程序实现可伸缩性,加过执行速度,节省内存
为什么说临时对象池中的值会被及时地清理掉?
存储值所用的数据结构?
内部实现
本地池与各个 G 的对应关系
获取临时对象的步骤
使用
New
并不是开箱即用的,需要指定默认取值函数,否则调用 Get 方法可能得到 nil
Put
Get
最后依然无获取到,就会调用默认函数获取结果值,直接返回给调用方,其值并不会存入到对象池中
案例
fmt 包
集合操作
Map
map 并发安不安全?只读是线程安全的,同时读写、同时写写不是线程安全的,会报panic。
键类型的选择?必须支持判等操作
线程安全的 map
Map + 读写锁(sync.RWMutex)
sync.Map
适合场景
内部机制
基本思想
存储结构
sync.Map 中 read 与 dirty 的互换
基础使用方式
动态类型封装
orcaman/concurrent-map
适用场景
内部机制:Map + 分片锁
基础使用方式
Slice
切片并发安不安全? slice在并发执行中不会报错,但是数据会丢失
线程安全的 list
加锁
使用 channel 串行化操作
参考资料
Uber工程师对真实世界并发问题的研究
0 条评论
下一页