go的channel

经验

  • 不使用共享内存来通信
  • 使用通信来共享内存

channel的优点

  • 避免协程的竞争和数据冲突的问题
  • 更高级的抽象,降低开发的难度,增加程序的可读性
  • 模块间容易解耦,增强扩展性和可维护性
1
2
3
4
5
6
7
8
9
10
11
12
13
14

func watch(ch chan int) {
if <-ch == 1 {
fmt.Println("get 1")
}
}

func main() {
ch := make(chan int, 0)

go watch(ch)

ch <- 1
}

channel的原理

``image-20240224195143474

环形缓存可以大幅降低GC的开销

image-20240224200009876

数据发送的原理

  • 编译阶段,会把 c<-元素 转化为 runtime.chansend1()
  • 直接传递,将数据直接拷贝到目标变量
  • 放入缓存,将数据放入环形缓存,成功返回
  • 休眠等待,将自己包装后放入sendq,休眠

数据接收的原理

  • 有等待的G,从G接收(无缓存)
  • 有等待的G,从缓存接收(缓存满了)
  • 接收缓存(缓存没满,直接send到缓存中通)
  • 无等待的G,休眠(什么都没有,干等)

非阻塞channel1

  • 使用select 可以使用channel的非阻塞特性
  • 使用timer配合select可以实现超时的特性
1
2
3
4
5
6
7
8
9
10
11
12
ch1 := make(chan struct{}, 10)
ch2 := make(chan struct{}, 0)

timer := time.NewTimer(time.Second * 3)
select {
case <-timer.C:
fmt.Println("time over")
case <-ch1:
fmt.Println("ch1 get v")
case ch2 <- struct{}{}:
fmt.Println("ch send v")
}

go的channel
http://example.com/2024/02/24/go的channel/
作者
Forrest
发布于
2024年2月24日
许可协议