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