一 channel 的基本介绍
1 channle 本质就是一个队列。
2 数据是先进先出(FIFO : first in first out)。
3 线程安全,多 goroutine 访问时,不需要加锁,就是说 channel 本身就是线程安全的。
4 channel 是有类型的,一个 string 的 channel 只能存放 string 类型数据。
5 示意图
二 定义和声明 channel
1 语法
var 变量名 chan 数据类型
2 举例
var intChan chan int // intChan 用于存放 int 数据
var mapChan chan map[int]string // mapChan 用于存放 map[int]string 类型
var perChan chan Person // perChan 用于存放 Person 结构体
var perChan2 chan *Person // perChan2 用于存放 *Person 指针
...
3 说明
-
channel 是引用类型。
-
channel 必须初始化才能写入数据,即 make 后才能使用。
-
管道是有类型的,intChan 只能写入 整数 int。
三 channel 使用的注意事项
- channel 中只能存放指定的数据类型。
- channle 的数据放满后,就不能再放入了。
- 如果从 channel 取出数据后,可以继续放入。
- 在没有使用协程的情况下,如果 channel 数据取完了,再取,就会报 dead lock。
四 代码
package main
import (
"fmt"
)
func main() {
// 演示一下管道的使用
// 1 创建一个可以存放 3 个int类型的管道
var intChan chan int
intChan = make(chan int, 3)
// 2 intChan 实际是一个引用
fmt.Printf("intChan 的值=%v intChan本身的地址=%p\n", intChan, &intChan)
// 3 向管道写入数据
intChan <- 10 // 写入第 1 个数据
num := 211
intChan <- num // 写入第 2 个数据
intChan <- 50 // 写入第 3 个数据
// 如果从 channel 取出数据后,可以继续放入
<-intChan // 表示取出第 1 个数据,并将它抛弃
intChan <- 98 // 注意点:当我们给管道写入数据时,不能超过其容量,这里还是可以写入的,因为已经抛弃了一个数据
// 4 管道的长度和cap(容量)
fmt.Printf("channel len= %v cap=%v \n", len(intChan), cap(intChan)) // 3, 3
// 5 从管道中读取数据
var num2 int
num2 = <-intChan
fmt.Println("num2=", num2) // 211
fmt.Printf("channel len= %v cap=%v \n", len(intChan), cap(intChan)) // 2, 3
// 6 在没有使用协程的情况下,如果我们的管道数据已经全部取出,再取就会报告 deadlock
num3 := <-intChan // 取出 50
num4 := <-intChan // 取出 98
// 已经取完了,再取就报错
// num5 := <-intChan
fmt.Println("num3=", num3, "num4=", num4 /*, "num5=", num5*/)
}
五 测试
intChan 的值=0xc042078080 intChan本身的地址=0xc042070018
channel len= 3 cap=3
num2= 211
channel len= 2 cap=3
num3= 50 num4= 98