一、介绍

Golang 设计模式: 不要通过共享内存来通信,而要通过通信实现内存共享

channel是基于通信顺序模型(communication sequential processes, CSP)的并发模式,可以让一个 goroutine 发送特定值到另一个 goroutine 的通信机制

channel中的数据遵循先入先出(First In First Out)的规则,保证收发数据的顺序

二、结构

channel的源码在runtime包下的chan.go文件, 参见chan.go

以下时channel的部分结构:

其中:

 

1 结构图

其中:

三、channel的创建

1 声明channel类型

其中:

类型:channel内的数据类型,golang支持的合法类型

声明的channel此时还是nil,需要配合make函数初始化之后才能使用

2 创建channel

  

四、向channel发送数据

1 发送数据的格式

2 写数据的过程

1) 流程图如下:

 

其中:

2) 过程描述:

五、从channel接收数据

1 接收数据的格式

1) 阻塞接收数据

程序阻塞直到收到数据并赋值

 

2) 非阻塞接收数据

非阻塞的通道接收方法可能造成高的 CPU 占用

  

3) 接收数据并忽略

程序阻塞直到接收到数据,但接收到的数据会被忽略

  

4) 循环接收

channel是可以进行遍历的,遍历的结果就是接收到的数据

5) SELECT语句接收

select 的特点是只要其中有一个 case 已经完成,程序就会继续往下执行,而不会考虑其他 case 的情况在一个 select 语句中,Go语言会按顺序从头至尾评估每一个发送和接收的语如果其中的多条case语句可继续执行(即没有被阻塞),那么就从这些case语句中任意选择一条如果没有case语句可以执行(即所有的通道都被阻塞):  1) 如果有 default 语句,执行 default 语句,同时程序的执行会从 select 语句后的语句中恢复  2) 如果没有 default 语句,那么 select 语句将被阻塞,直到至少有一个case可以进行下去

  

2 读取数据的流程

1) 流程图如下:

其中:

2) 过程描述:

六、关闭channel

1 格式

2 过程描述

七、channel发送、接收数据过程可能产生的问题

1 向一个nil的channel发送/读取数据会一直堵塞下去?该如何唤醒?

会一直堵塞下去,不会被唤醒,可能会造成泄露,这是一个BUG

2 等待发送队列(sendq)中有数据,如果一直没有gouruntine从channel里面读数据会不会造成泄漏?

会造成泄露,channel用完了,最好要close

3 向已经关闭的channel读/写数据会发生什么?

写已经关闭的 channel 会触发panic

读已经关闭的 channel,能一直读到数据:

1) 如果 channel 关闭前,buf内有元素还未读,会正确读到 channel 内的值,且返回的第二个 bool 值为 true

2) 如果 channel 关闭前,buf内有元素已经被读完,channel 内无值,返回 channel 元素的零值,第二个 bool 值为 false

4 触发 panic 的三种情况

1) 向一个关闭的 channel 进行写操作

2) 关闭一个为 nil 的 channel

3) 重复关闭一个 channel

标签: