GO语言入门学习之Channel管道
老男孩IT教育
技术博客
2021年2月1日 15:08
Channel 是Go中的一个核心类型,你可以把它看成一个管道。Channel是引用类型,操作符是箭头 <- 。
Channel 是Go中的一个核心类型,你可以把它看成一个管道。Channel是引用类型,操作符是箭头 <- 。
Channel 是 CSP 模式的具体实现,用于多个 goroutine 通讯。其内部实现了同步,确保并发安全。
Channel 是线程安全的,先进先出,多个goroutine同时访问,不需要加锁,channel是有类型的,一个整数的channel只能存放整数。
Channel定义
第一种,channel声明
声明int类型的chan
var ch chan int
声明string类型的chan
var ch chan string
声明map类型chan
var ch chan map[int]string
第二种,使用make定义,无缓冲channel
var ch1 chan int = make(chan int)
var ch2 = make(chan int)
ch3 := make(chan int)
第三种,使用make定义,有缓冲channel
var ch1 chan int = make(chan int, 10)
var ch2 = make(chan int, 10)
ch3 := make(chan int, 10)
第四种,只读channel
var ch1 <-chan int
var ch2 <-chan int = make(<-chan int, 10)
var ch3 = make(<-chan int, 10)
ch4 := make(<-chan int, 10)
第五种,只写channel
var ch1 chan<- int
var ch2 chan<- int = make(chan<- int, 10)
var ch3 = make(chan<- int, 10)
ch4 := make(chan<- int, 10)
Channel特点
无缓冲的与有缓冲channel有着重大差别,那就是一个是同步的 一个是非同步的。
比如
无缓冲chan:ch1:=make(chan int)
有缓冲chan:ch2:=make(chan int,1)
无缓冲: ch1<-1 不仅仅是向 c1 通道放 1,而是一直要等有别的携程 <-ch1 接手了这个参数,那么ch1<-1才会继续下去,要不然就一直阻塞着。
有缓冲: ch2<-1 则不会阻塞,因为缓冲大小是1(其实是缓冲大小为0),只有当放第二个值的时候,第一个还没被人拿走,这时候才会阻塞。
缓冲区是内部属性,并非类型构成要素。
普通 channel 可以隐式转为只读channel或只写channel。
package main
var ch = make(chan int, 3)
var send chan<- int = ch
var recv <-chan int = ch
func main() {
}
只读channel或只写channel不能转为普通 channel。
package main
func main() {
var send chan<- int
var recv <-chan int
ch1 := (chan int)(send)
ch2 := (chan int)(recv)
}
编译错误:
./main.go:7:19: cannot convert send (type chan<- int) to type chan int
./main.go:8:19: cannot convert recv (type <-chan int) to type chan int
Channel操作
使用内置函数 len() 返回未被读取的缓冲元素数量,使用内置函数 cap() 返回缓冲区大小。
package main
import "fmt"
func main() {
ch1 := make(chan int)
ch2 := make(chan int, 3)
ch2 <- 1
fmt.Printf("ch1 缓冲元素数量:%v,缓冲区大小:%v\n", len(ch1), cap(ch1))
fmt.Printf("ch2 缓冲元素数量:%v,缓冲区大小:%v\n", len(ch2), cap(ch2))
}
运行结果:
ch1 缓冲元素数量:0,缓冲区大小:0
ch2 缓冲元素数量:1,缓冲区大小:3
channel 写入、读取操作:
package main
import "fmt"
func main() {
ch := make(chan int, 1)
// 写入chan
ch <- 99
// 读取chan
value, ok := <-ch
if ok {
fmt.Printf("读取chan:%v\n", value)
}
}
channel 关闭操作:
1、使用内置函数 close() 进行关闭 chan。
2、chan关闭之后,for range遍历chan中已经存在的元素后结束。
3、没有使用for range的写法需要使用,val, ok := <- ch进行判断chan是否关闭。
package main
import "fmt"
func main() {
ch := make(chan int, 5)
ch <- 1
ch <- 2
ch <- 3
close(ch)
for {
val, ok := <-ch
if ok == false {
fmt.Println("chan is closed")
break
}
fmt.Println(val)
}
}
注意:向已经关闭的 channel 发送数据会引发 panic 错误。
package main
func main() {
ch := make(chan int, 1)
close(ch)
ch <- 100
}
运行错误:
panic: send on closed channel
老男孩教育在IT培训方面,十分注重理论+实战相结合,全部为名师手把手的带领“课堂即实战式”教学。其中的4项学习思想方针(目标、方法、努力、坚持)和6重教学理念(重目标、重思路、重方法、重实践、重习惯、重总结)已深入广大IT网友及学员的内心,逐步成为互联网IT行业内教育经典。编程思想,历来是老男孩教育的重中之重,学会而且要明白为何要如此操作才能行。
推荐阅读:
