Channel
Channel本质是一个队列
多goroutine访问时不需要加锁,Channel天然线程安全
channel有类型,只能写入相同类型
channel是引用类型
channel必须初始化才能写入数据,make分配内存
声明
var intChan chan int intChan = make(chan int, 3)
java不是很熟悉,感觉chan有点像java的原子类
存入取出
intChan<- xxx //存入a := <= intChan//取出
管道不会自然增长,不能超过容量,不能从空的管道里取出数据,会上DeadLock
如果想要存储任意类型的管道,可以用空借口
var allChan chan interface{}
但是,取出的时候注意类型断言
close(intChan)
channel关闭之后就不能再写入了,但是能继续读出
关闭之后能用for-range来遍历,如果不关闭的话会出现死锁
死锁的情况很多,建议多找几篇文章看看,写写实操一下
空的缓冲chan相当于无缓冲的chan,无缓冲的chan需要接收者,传入者,否则就会死锁,注意及时关闭
只向管道内写入,不读取就会deadlock,读得慢没有关系
关键是要给每个管道安排一个发送者,和接收者!!!
一个简单的死锁分析
package mainimport ( "fmt" "time")func write(intChan chan int) { for i := 0; i < 5; i++ { fmt.Println("写入: ", i) intChan <- i time.Sleep(time.Second) } //close(intChan)}func read(intChan chan int, exitChan chan bool) { for { val, ok := <-intChan if !ok { break } fmt.Println("读到", val) } exitChan <- true close(exitChan)}func main() { intChan := make(chan int, 20) exitChan := make(chan bool, 1) go write(intChan) go read(intChan, exitChan) for { _, ok := <-exitChan if !ok { break } }}
输出
写入: 0读到 0写入: 1读到 1写入: 2读到 2写入: 3读到 3写入: 4读到 4fatal error: all goroutines are asleep - deadlock!goroutine 1 [chan receive]: main.main() E:/JetBrains/GoLandSpace/src/go_code/project01/main/hello.go:36 +0xe8 goroutine 7 [chan receive]: main.read(0x0?, 0x0?) E:/JetBrains/GoLandSpace/src/go_code/project01/main/hello.go:19 +0x99 created by main.main E:/JetBrains/GoLandSpace/src/go_code/project01/main/hello.go:33 +0xd9 Process finished with the exit code 2
下面是个人的分析,不一定对,有大佬可以来指正
如果我们不close,channel是可以读的,我们可以边读,边写,并且,读的速度是可以更慢或者更快的,go底层会通过上下文自行判断。
但是这里,我们写的协程,我们关闭channel,在程序运行完之后自行关闭,此时我们读的协程会卡在intChan,等待读入,但是此时还不会报错,因为协程会因为主线程结束而结束。但是后面的exitChan会导致报错
package mainimport ( "fmt" "time")func write(intChan chan int) { for i := 0; i < 5; i++ { fmt.Println("写入: ", i) intChan <- i time.Sleep(time.Second) } //close(intChan)}func read(intChan chan int, exitChan chan bool) { for { val, ok := <-intChan if !ok { break } fmt.Println("读到", val) } fmt.Println("到了这里") //exitChan <- true //close(exitChan)}func main() { intChan := make(chan int, 20) exitChan := make(chan bool, 1) go write(intChan) go read(intChan, exitChan) time.Sleep(time.Second * 10) //for { // _, ok := <-exitChan // if !ok { // break // } //}}
这样并没有报错,并且发现到了这里没有打印,说明read函数作为intChan的接收者一直在等待,这时候。
但是,主线程运行到下面的for的时候,此时exitChan是空的,因为intChan一直在死循环等待,所以触发了死锁
只读只写
var chanIn chan<- int//只写
var chanOut <-chan int//只读
select {case …}可以安全地取出数据文章来源:https://www.toymoban.com/news/detail-691267.html
使用recover捕获协程终端 panic文章来源地址https://www.toymoban.com/news/detail-691267.html
到了这里,关于Golang Channel详解:安全并发通信与避免死锁方法的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!