channel相关

channel基础

1、channel的初始化

ch := make(chan int64, 10)

2、channel的关闭

close(ch)panic

3、channel的数据统计

len(ch)cap(ch)

无缓冲的channel

当初始化channel不指定通道容量(或指定容量为0)时,该通道为无缓冲channel;

1、无缓冲channel的特性

一个无缓冲channel的发送操作将导致发送者goroutine的阻塞,直到另一个goroutine在相同的channel上执行接收操作
同理接收者阻塞,直到另一个goroutine发送

2、无缓冲channel的用途

  1. 同步操作。如事件A(goroutineA)必须在事件B(goroutineB)之前完成,则在goroutineA中完成时间A后发送无缓冲channel,goroutineB中接收到统一channel的消息再执行事件B
  2. Pipeline. 可以使用多个无缓冲channel连接多个goroutine,形成一个管道(pipeline)。

3、goroutine泄露

func testGoroutineLeak() {
	ch := make(chan int64)
	go func() { ch <- 64 }()
	go func() { ch <- 52 }()
	go func() { ch <- 41 }()
	<-ch
}

当无缓冲channel的发送者goroutine数量和接受者goroutine数量不一致时,会导致较多一方的goroutine阻塞,且无法自动回收(goroutine不会自动被回收),造成goroutine泄露

单方向的channel

  1. 双向channel可以隐式转换为单方向channel
  2. 反之不可

有缓冲的channel

当初始化channel时指定通道容量,该通道为有缓冲的channel;

有缓冲的通道可以一定程度上解决上述“无缓冲通道”引发的goroutine泄露问题

channel的常用操作示例

1、使用for range读channel

场景:需要轮询channel中的数据
优点:当channel关闭时自动退出循环,无需额外判断channel是否关闭;
用法:

for x := range ch {
do_something(x)
}

2、使用_, ok判断channel是否关闭

场景:读channel,但不确定channel是否关闭
优点:可以通过ok值明确判断channel是否关闭,不受channel类型本身0值的影响
用法:

if x, ok := <- chan {
do_something(x)
}

3、使用select处理多个channel

场景:

  1. 需要读取/写入多个通道时,不因一个通道的阻塞影响另一个通道的写入
  2. 需要给读取/写入操作增加超时时间

4、消息广播

close(ch)

channel底层源码实现

channel面试题

同一个协程里,对一个无缓冲的channel同时发送和接收数据有什么问题?有缓冲呢?

同一个协程是串行的,无法同时做“发送”和“接收”两个事情,只能先发后收,或者先收后发。

  1. 无缓冲:会造成goroutine阻塞,协程对一个无缓冲的channel发送(或者接收)消息会阻塞;
  2. 有缓冲:正常执行。
    • 但是没必要?同一个协程的通信直接函数调用或者串行代码逻辑

channel的应用场景?

0 + 1*1 + 2*2 + 3*3...

channel和锁的对比?

channel是线程安全的,使用channel可以解决数据并发问题;但是channel解决并发问题的场景是“数据的流动性”,数据在动,channel不动(提供了串行获取流动数据的能力)

锁mutex也可以解决并发访问资源的问题;但是mutex更多解决“静态数据”的问题,即数据不动,某段时间控制只给一个协程访问