Go Channel 深入理解与实践指南
前言
最近在面试过程中遇到了 channel 相关问题,发现自己的回答还有改进空间,因此整理了这篇文章来深入理解 Go 的 channel 机制。作为支付业务开发,channel 在并发处理中扮演着重要角色。
Channel 存在的价值
Channel 是 Go 语言并发编程的核心特性,主要解决以下问题:
- Goroutine 间的安全通信:避免共享内存带来的竞态条件
- 同步协调:控制 goroutine 的执行时序
- 数据传递:在不同 goroutine 间传递数据
- 解耦合:通过消息传递而非共享状态进行协作
正如 Go 的设计哲学:"Don't communicate by sharing memory; share memory by communicating"
Channel 的定义和创建
// 声明 channel
var ch chan int
// 创建无缓冲 channel
ch = make(chan int)
// 创建有缓冲 channel
ch = make(chan int, 10)
// 一步创建
ch := make(chan int, 5)
Channel的基本操作
发送数据(写入)
ch <- 42
接收数据
value := <-ch
value,ok := <-ch //接收并检查channel状态
关闭channel
close(ch)
注意事项:
- 只有发送方应该关闭channel
- 向已关闭的channel发送数据会发生panic
- 对于已经关闭的channel使用close会发生panic
- 从已经关闭的channel中取数据会返回0
有缓冲&无缓冲
无缓冲channel (同步channel)
ch := make(chan int)
这种必须同时有两个goroutine去进行存数与取数
有缓冲channel
ch := make(chan int,3)
当缓冲区满的时候,向channel写数据的goroutine会阻塞 当缓冲区空的时候,向channel读数据的goroutine会阻塞 有缓冲的channel,写数据的channel可以在完成写数据之后直接close,此时取数据的goroutine可以通过如下方式判断是否取完
val,ok := <-ch
if !ok{
fmt.println("数据已被取完")
}
单向Channel
在go中可以通过控制传参来控制某个func只能够存/取channel中的数据
Channel高级用法
Channel大部分高级用法我理解都是生产者-消费者的变形与拓展
Channel的使用最佳实践
- 由发送方关闭channel
- 不要在接受方关闭channel
- 不要关闭有多个发送者的channel
- 使用context控制超时
在支付业务中的应用场景
- 异步通知
- 在支付场景中会有很多的异步回调通知,以及webhook,这部分如果使用同步会让用户体验很不好,目前业务中使用的方式是先记录用户的参数然后返回,之后使用记录的参数去执行后续的支付链路