通道
通道(channel)是Go语言提供的一种在gorountine之间进行数据创术的通信机制。通道的声明非常简单,只需要使用chan
关键字即可,关闭则需要使用close函数。
注意:通过close函数关闭channel不是必须的。不主动关闭的通道,垃圾回收器会自动回收。文件操作的close姿势必须的。
创建通道
借助 make 函数
-
先声明,后初始化
var ch1 chan int // 声明一个传输 int 的通道 ch1 = make(chan int) // 初始化通道 // ch1 = make(chan int, 3)
-
声明并初始化
ch2 := make(chan int)
channel写入数据
<-
表达式向channel中写入数据
ch = make(chan int) // 创建int通道 ch
ch <- 5 // 通道中写入 5
channel读出数据
->
表达式从channel中读出数据
ch = make(chan int) // 创建int通道 ch
ch <- 5 // 通道中写入 5num := <-ch // 从通道中读取数据,放入 ch 中
阻塞式读写
通道channel写数据时,保证通道未满。否则,会阻塞写入,直到channel中的数据被读取,channel不满,此时写入数据。
通道channel读数据时,保证通道非空。否则,会阻塞读取,直到channel中有数据,然后读出数据。
缓冲channel和无缓冲channel
创建
ch1 := make(chan int) // 创建无缓冲 channel
ch2 := make(chan int, 3) // 创建缓冲大小为 3 的channel
- channel的摩尔你初始值是
nil
读写
- 无缓冲通道。写入一个数据后,立即阻塞,直到这个数据被取出。
- 有缓冲通道。当准备往通道中写入数据时,如果通道已满,则阻塞,直到通道不满。否则,直接写入,即使写入数据后,通道满了,也不阻塞。
简单的说,无缓冲通道的写阻塞发生在数据写入后,有缓冲通道的阻塞发生在数据写入前,通道已满。
小技巧:缓冲channel的缓冲区元素个数和缓冲区容量,可以通过len
函数和cap
函数来返回。
误区
- 不能把无缓冲通道看成缓冲大小为 1 1 1的有缓冲通道
ch := make(chan int) // 无缓冲通道
ch := make(chan int, 1) // 有缓冲通道
给出一段代码示例,辅助理解:
- 使用上面两种通道,相同的代码结果是不一样的。
package mainimport "fmt"
import "time"func main() {c := make(chan int) // 运行结果输出一个 6// c := make(chan int, 1) // 运行结果输出两个 6go w(c, 6)time.Sleep(1*time.Second)
}func w(c chan int, x int){fmt.Println(x)c <- xclose(c)fmt.Println(x)
}
注意: 当主goroutine结束的时候,所有其他的goroutine都会被强制结束。
channel作为函数参数
Go语言在channel做函数参数的时候可以指定通道的方向,也就是指定该通道是发送数据还是接受数据。
通道分两种类型:无方向通道和双向通道,默认创建的是双向通道。
func f1(c chan int) {} // c 是 双向通道, 可读可写
func f2(c chan<- int) {} // c 是 写通道, 只能写数据,不能读数据
func f3(c <-chan int) {} // c 的 读通道,只能读数据,不能写数据
注意:双向通道以指定方向的参数方式,进行隐式转换成读通道或写通道。反之,则不行。