channel简介
多线程传递数据的方式一般是通过共享内存,为了解决线程的竞争,需要限制同一时间访问这些线程的数量(互斥锁)。
golang采用channel(通道)进行协程间的数据传递,信道分为无缓冲通道和有缓冲通道,对于无缓冲通道来说,发送消息和接收消息都是阻塞的。无缓冲通道在发送和接受消息时协程出于挂起的状态,除非另一端准备好,否则协程是无法继续执行下去的。
channel的应用
代码1演示如下
package main
import (
"fmt"
"time"
)
func main() {
ch := make(chan string)
//发送操作在协程中执行,如不在协程中操作,则主函数报错
go send(ch,"test")
go recv(ch)
time.Sleep(time.Second)
//循环发送消息
ch1 := make(chan int)
go func() {
for i:=0;i<=5 ;i++ {
fmt.Println("这是写入的",i)
ch1 <- i
}
}()
go func() {
//for循环遍历channel数据
for i:=range ch1 {
fmt.Println("这是读取的",i)
}
}()
//关闭通道
defer close(ch1)
}
func send(ch chan string,cnt string) {
ch <- cnt
}
func recv(ch chan string) {
fmt.Println(<-ch)
}
死锁deadlock
当main函数执行到send方法时就变成挂起状态,而且并没有其他的协程来负责接受消息,下一行的代码永远无法执行,系统会自动判断为超时而抛出异常。这种所有线程或者集成都在等待资源释放的情况,我们成为死锁 deadlock
关于死锁的演示代码2如下所示
package main
import (
"fmt"
"time"
)
func main() {
ch := make(chan string)
send(ch,"test")
time.Sleep(time.Second)
}
func send(ch chan string,content string) {
ch <- content
}
func recv(ch chan string) {
fmt.Println(<-ch)
}
程序执行结果:
[root@d312d24bef6f day1118]# go run main.go
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan send]:
main.send(...)
/data/webroot/go/test/day1118/main.go:17
main.main()
/data/webroot/go/test/day1118/main.go:11 +0x65
exit status 2
解决方式:
1,写操作在在协程中执行如代码1中展示
2,写操作非协程时,在写操作前加一个协程的读操作 代码3如下
func main() {
ch := make(chan string)
go recv(ch)
send(ch,"test")
time.Sleep(time.Second)
}
3,创建channel为缓冲通道,缓冲通道就是存储数据的channel,通过make函数的长度参数(默认为0说明不能存储数据,写入后会发生阻塞,直到数据被读取)来控制。
代码4如下
func main() {
ch := make(chan string,1)
send(ch,"test")
recv(ch)
time.Sleep(time.Second)
}
单向通道
package main
import (
"fmt"
"time"
)
func main() {
var sendOnlyCh chan<- string //单向发送通道
var recvOnlyCh <-chan string //单向接受通道
ch := make(chan string)
sendOnlyCh = ch
recvOnlyCh = ch
go sendOnly(sendOnlyCh)
go reacOnly(recvOnlyCh)
time.Sleep(time.Second)
}
func sendOnly(ch chan<- string){
ch <- "hahaha"
}
func reacOnly(ch <-chan string){
fmt.Println(<-ch)
}