通道类型是 go 自带的、唯一一个可满足并发安全的类型。
使用 make 声明并初始化一个通道。
一个通道相当于一个 FIFO 队列。元素的发送和接收都用到接送操作符 <-。
package main
import "fmt"
func main(){
ch1 := make(chan int, 3) // 声明并初始化了一个元素类型为 int、容量为 3 的通道 ch1
ch1 <- 2
ch1 <- 1
ch1 <- 3
elem1 := <-ch1
fmt.Printf("The first element received from channel ch1: %v\n", elem1)
}
通道的发送和接收操作的基本特性:对于同一个通道,发送操作之间是互斥的,接收操作之间也是互斥的。
发送和接收操作被阻塞的时机:
package main
func main(){
ch1 := make(chan int, 1)
ch1 <- 1
// ch1 <- 2 // 通道满,阻塞
ch2 := make(chan int, 1)
// elem, ok := <- ch2 // 通道空,阻塞
// _, _ = elem, ok
ch2 <- 1
var ch3 chan int
// ch3 <- 1 // 通道为 nil,永久阻塞
// <- ch3 // 通道为 nil,永久阻塞
_ = ch3
}
发送和接收操作引发 panic 的时机:
- 对已经关闭的通道进行收发操作。
- 关闭一个已经关闭的通道。一般让发送方关闭通道,而不是接收方。
package main
import "fmt"
func main(){
ch1 := make(chan int, 2)
// 发送方
go func() {
for i := 0; i<5; i++ {
fmt.Printf("Sender: sending element %v...\n", i)
ch1 <- i
}
fmt.Println("Sender: close the channel...")
close(ch1)
}()
// 接收方
for {
elem, ok := <- ch1 // ok 为 false,说明通道已关闭
if !ok {
fmt.Println("Receiver: closed channel")
break
}
fmt.Printf("Receiver: received an element: %v\n", elem)
}
fmt.Println("End.")
}