go channel详解

163 阅读2分钟

Go Channel 深入理解与实践指南

前言

最近在面试过程中遇到了 channel 相关问题,发现自己的回答还有改进空间,因此整理了这篇文章来深入理解 Go 的 channel 机制。作为支付业务开发,channel 在并发处理中扮演着重要角色。

Channel 存在的价值

Channel 是 Go 语言并发编程的核心特性,主要解决以下问题:

  1. Goroutine 间的安全通信:避免共享内存带来的竞态条件
  2. 同步协调:控制 goroutine 的执行时序
  3. 数据传递:在不同 goroutine 间传递数据
  4. 解耦合:通过消息传递而非共享状态进行协作

正如 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,这部分如果使用同步会让用户体验很不好,目前业务中使用的方式是先记录用户的参数然后返回,之后使用记录的参数去执行后续的支付链路