Go channel 知识点

422 阅读1分钟

Go channel

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第15天,点击查看活动详情 >>

1. 基础

channel是什么:通道可以使一个goroutine发送特定值到另一个goroutine的通信机制。通道相当与一个先进先出(FIFO)的队列,使用map数据结构实现。channel 中包括 buffer、sendx 和 recvx 收发的位置(ring buffer 记录实现)、sendq、 recv。无缓冲的 channel 是同步的,而有缓冲的 channel 是非同步的。

Channel的操作符是箭头<-,箭头指向是数据的流向

channel必须先创建再使用,make(chan int)

channel 中使用了 ring buffer(环形缓冲区) 来缓存写入的数据。recvx 指向最早被读取的数 据,sendx 指向再次写入时插入的位置。当 channel 因为缓冲区不足而阻塞了队列,则使用双向链表存储。

2.基本操作

应用场景

channel适合运用在数据流动的地方,数据在多个协程中流动,比如说

  1. 任务定时:超时处理/定时任务
  2. 解耦生产者和消费者
  3. 控制并发数,并发控制
  4. 事件订阅和广播
  5. 同步与异步

常用操作:

  1. 使用for range读channel
  2. 使用_ , ok判断channel是否关闭,ok 表示接收到的值是否是在 channel 被关闭前发送的。true表示读到数据,通道没有关闭;false 表示通道关闭,读不到数据
  3. select 处理多个channel

3. 注意事项

3.1 和锁的区别

  • channel关注的是并发问题的数据流动,适用于数据在多个协程中流动的场景。

    1. 传递数据的所有权,即把某个数据发送给其他协程
    2. 分发任务,每个任务都是一个数据
    3. 交流异步结果,结果是一个数据
  • 而mutex关注的是是数据不动,某段时间只给一个协程访问数据的权限,适用于数据位置固定的场景。

    1. 缓存
    2. 状态

3.2 channel使用

  • 向为nil的channel发送数据,会造成永远阻塞

    • 空通道=无缓冲通道,channel中的发送操作将会被阻塞,直到另一个goroutine在对应的通道执行接受操作。
  • 如果从一个 nil 的 channel 中接收数据,也会造成永久阻塞。
  • 给一个已经关闭的 channel 发送数据, 会引起 panic
  • 从一个已经关闭的 channel 接收数据, 如果缓冲区中为空,则返回一个零值。

同一个协程中,对无缓冲的channel同时发送和接受数据

  • 同一个协程里,不能对无缓冲channel同时发送和接收数据,如果这么做会直接报错死锁。
  • 对于一个无缓冲的channel而言,只有不同的协程之间一方发送数据一方接受数据才不会阻塞。channel无缓冲时,发送阻塞直到数据被接收,接收阻塞直到读到数据。

参考

总结了才知道,原来channel有这么多用法!