📌Golang📌基础📌K-channel通道.txt
Golang引用类型channel是CSP模式的具体实现,用于多个goroutine通讯。其内部实现了同步,确保并发安全。
channel概念
a. 类似unix中管道(pipe)
b. 先进先出
c. 线程安全,多个goroutine同时访问,不需要加锁
d. channel是有类型的,一个整数的channel只能存放整数
channel声明:
var 变量名 chan 类型
通道是引用类型,通道类型的空值是nil。
channel需要使用make函数初始化之后才能使用。创建channel的格式如下:
make(chan 元素类型, [缓冲大小])
无缓冲的与有缓冲channel有着重大差别,那就是一个是同步的 一个是非同步的。
无缓冲通道上的发送操作会阻塞,直到另一个goroutine在该通道上执行接收操作,这时值才能发送成功,两个goroutine将继续执行。
相反,如果接收操作先执行,接收方的goroutine将阻塞,直到另一个goroutine在该通道上发送一个值。
使用无缓冲通道进行通信将导致发送和接收的goroutine同步化。因此,无缓冲通道也被称为同步通道。
内置函数len返回未被读取的缓冲元素数量,cap返回缓冲区大小。
通道有发送(send)、接收(receive)和关闭(close)三种操作。发送和接收都使用<-符号。
var ch = make(chan int, 1)
ch <- 10 // 将一个值发送到通道中
//ch <- 20 // 会造成死锁
x := <-ch // 从ch中接收值并赋值给变量x
println(x)
<-ch // 从ch中接收值,忽略结果
close(ch) // 关闭通道
通道无接收方时,当通道无缓冲或缓冲已满,会产生deadlock。
func main() {
var ch = make(chan int)
ch <- 10 //此处换成 <-ch 同样会产生deadlock
}
解决方法:开启一个goroutine去接收值
func recv(c chan int) {
i := <-c
println("接收成功", i)
}
func main() {
var ch = make(chan int)
go recv(ch)
ch <- 10
println("发送成功")
}
关闭后的通道有以下特点:
1.对一个关闭的通道再发送值就会导致panic。
2.对一个关闭的通道进行接收会一直获取值直到通道为空。
3.对一个关闭的并且没有值的通道执行接收操作会得到对应类型的零值。
4.关闭一个已经关闭的通道会导致panic。
channel关闭后,就不能取出数据了。
for...range遍历chan中已经存在的元素后结束。
还可以使用 v, ok := <- ch 判断chan是否关闭。
func main() {
ch1 := make(chan int)
ch2 := make(chan int)
// 开启goroutine将数据发送到ch1中
go func() {
ch1 <- 1
ch1 <- 2
ch1 <- 3
close(ch1)
}()
// 开启goroutine从ch1中接收值,并将该值的平方发送到ch2中
go func() {
for {
i, ok := <-ch1 // 通道关闭后再取值ok=false
if !ok {
break
}
ch2 <- i * i
}
close(ch2)
}()
// 在主goroutine中从ch2中接收值打印
for i := range ch2 { // 通道关闭后会退出for range循环
println(i) // 依次输出 1 4 9
}
} // 注掉关闭ch1或ch2会产生deadlock
只读chan的声明:
var 变量名 <-chan 类型
只写chan的声明:
var 变量名 chan<- 类型
可以将channel隐式转换为单向队列,只收或只发。不能将单向channel转换为普通channel。
c := make(chan int, 3)
var send chan<- int = c // send-only
var recv <-chan int = c // receive-only
send <- 1
// <-send // Error: receive from send-only type chan<- int
if val, ok := <-recv; ok {
println(val)
}
// recv <- 2 // Error: send to receive-only type <-chan int
channel是第一类对象,可传参 (内部实现为指针) 或者作为结构成员。