今天在看到Go中的channel时,就自己动手试了一下这个数据结构,先贴原始代码:
package main
import (
"fmt"
"time"
)
func main() {
ch :=make(chan string)
ch <-"abc"
ch <-"def"
for {
fmt.Println(<-ch)
}
}
乍一看没毛病,但就是这么简单的一个测试运行就直接报错了:
D:\Go\bin\go.exe build -o C:\Users\wangxihe\AppData\Local\Temp\___go_build_ChannelTest_go.exe D:/WorkSpace/Go/GoLearning/ChannelTest.go #gosetup
C:\Users\wangxihe\AppData\Local\Temp\___go_build_ChannelTest_go.exe #gosetup
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan send]:
main.main()
D:/WorkSpace/Go/GoLearning/ChannelTest.go:12 +0x65
Process finished with exit code 2
这就往里面写了两个字符串,然后再读出来,怎么就死锁了呢?
然后我就查到了这位大佬的资料,先贴上链接以示尊敬:https://blog.csdn.net/u011328417/article/details/89473323
下面附上我自己综合别的资料的理解:
首先,使用ch :=make(chan string)
创建的channel是无缓存的,这就意味着<-ch
这句会被阻塞直到接收到数据才被执行。并且当使用ch <-"abc"
进行写的时候,协程也会被阻塞直到有语句对这个channel进行读操作,而main函数的执行在go语言中本身就是一个协程的执行,所以在执行到c<-'A’
的时候,执行main函数的协程将被阻塞,进而fmt.Println(<-ch)
也将被阻塞无法执行,所以发生了死锁。
根据这位大佬的方法,将读和写操作写在不同的协程中,修改代码如下:
package main
import (
"fmt"
"time"
)
func main() {
ch :=make(chan string)
go test(ch)
go print(ch)
time.Sleep(time.Millisecond)
}
func test(ch chan string) {
ch <-"abc"
ch <-"def"
}
func print(ch chan string) {
for {
fmt.Println(<-ch)
}
}
问题解决,不报错而且正常输出
GOROOT=D:\Go #gosetup
GOPATH=C:\Users\wangxihe\go #gosetup
D:\Go\bin\go.exe build -o C:\Users\wangxihe\AppData\Local\Temp\___go_build_ChannelTest_go.exe D:/WorkSpace/Go/GoLearning/ChannelTest.go #gosetup
C:\Users\wangxihe\AppData\Local\Temp\___go_build_ChannelTest_go.exe #gosetup
abc
def
Process finished with exit code 0
综上所述,这一切的问题好像都是没有缓存引起的,那么理论上来说,如果使用有缓存的channel是否就可以解决了呢?
附上更改后的代码:
package main
import "fmt"
func main() {
ch :=make(chan string,100)
ch <-"abc"
ch <-"def"
for {
fmt.Println(<-ch)
}
}
运行发现可以输出结果但还是会报死锁的错:
GOROOT=D:\Go #gosetup
GOPATH=C:\Users\wangxihe\go #gosetup
D:\Go\bin\go.exe build -o C:\Users\wangxihe\AppData\Local\Temp\___go_build_cTest_go.exe D:/WorkSpace/Go/GoLearning/cTest.go #gosetup
C:\Users\wangxihe\AppData\Local\Temp\___go_build_cTest_go.exe #gosetup
abc
def
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan receive]:
main.main()
D:/WorkSpace/Go/GoLearning/cTest.go:10 +0x9f
Process finished with exit code 2
分析了一下,发现其实还是同样的问题,fmt.Println(<-ch)
又被阻塞了,于是就在读取之前先把channel关闭,代码如下:
package main
import (
"fmt"
)
func main() {
ch :=make(chan string,100)
ch <-"abc"
ch <-"def"
close(ch)
for i := range ch {
fmt.Println(i)
}
}
再次运行,问题解决:
GOROOT=D:\Go #gosetup
GOPATH=C:\Users\wangxihe\go #gosetup
D:\Go\bin\go.exe build -o C:\Users\wangxihe\AppData\Local\Temp\___go_build_cTest_go.exe D:/WorkSpace/Go/GoLearning/cTest.go #gosetup
C:\Users\wangxihe\AppData\Local\Temp\___go_build_cTest_go.exe #gosetup
abc
def
Process finished with exit code 0
大功告成,如果有哪里说的不对的欢迎各位大佬留言或者私信指教!
留下本菜鸟的邮箱:2681465985@qq.com