无缓冲与有缓冲:
c1:=make(chan int) 无缓冲
c2:=make(chan int,1) 有缓冲,可存放1个值
阻塞:不管事有缓存还是无缓存,当 channel 里面放满了数据(缓存不够了,无法继续写入),就会发生阻塞。
等待:主程序下,写入 channel (写满)的时候,会等待取走数据;读取 channel(无数据)等待写入数据。
主程序与线程:如果没有 channel 的牵绊,主程序不会等待线程。
1、如果在 main 主程序下发生阻塞,就会一直等待这个 channel 被消耗(因为 写和读都完成后,才算是一个完整的 channel 动作,带有原子性)
就会报错:
package main import ( "fmt" ) var c chan int func send(i int) { fmt.Println("send -> ", i) c <- i } func receive() { fmt.Println("receive : ", <-c) } func main() { count := 10 c = make(chan int) for i := 0; i < count; i++ { send(i) } for i := 0; i < count; i++ { receive() } } #go run test.go send -> 0 fatal error: all goroutines are asleep - deadlock! goroutine 1 [chan send]: main.send(0x0) D:/Golang/Test/src/goroutine.go:11 +0xc9 main.main() D:/Golang/Test/src/goroutine.go:23 +0x69 exit status 2
#报错原因:因为写入发送了阻塞,后面的 receive() 都没机会执行。
#解决方法:使用 go send(i) 或者 设置 channel 缓存数大于等于写入数量,这时,写入的时候不会发生阻塞。
2、如果在 goroutine(线程)发生阻塞,不会占用主程序进程,也不会等待 channel 被消耗,就不会报错。
因为主程序执行完就关闭进程了,线程就没了。
当然主程序可以读取 channel,把 channel 读取出来,这个时候主程序会等待把 channel 都读完才结束程序。
个人感觉使用 goroutine 去写 channel,通过主线程读 channel 才是正确的使用姿势。
#使用 goroutine
package main import ( "fmt" ) var c chan int func send(i int) { fmt.Println("send -> ", i) c <- i } func receive() { fmt.Println("receive : ", <-c) } func main() { count := 10 c = make(chan int) for i := 0; i < count; i++ { go send(i) } for i := 0; i < count; i++ { receive() } } //------输出------ E:/Go/bin/go.exe run goroutine.go [D:/Golang/Test/src] send -> 0 receive : 0 send -> 9 receive : 9 send -> 1 receive : 1 send -> 7 receive : 7 send -> 8 receive : 8 send -> 2 receive : 2 send -> 5 receive : 5 send -> 6 receive : 6 send -> 4 receive : 4 send -> 3 receive : 3 命令退出代码 0.
#增加缓存数量,不小于写入数
package main import ( "fmt" ) var c chan int func send(i int) { fmt.Println("send -> ", i) c <- i } func receive() { fmt.Println("receive : ", <-c) } func main() { count := 10 c = make(chan int, 10) for i := 0; i < count; i++ { send(i) } for i := 0; i < count; i++ { receive() } } //------输出----- E:/Go/bin/go.exe run goroutine.go [D:/Golang/Test/src] send -> 0 send -> 1 send -> 2 send -> 3 send -> 4 send -> 5 send -> 6 send -> 7 send -> 8 send -> 9 receive : 0 receive : 1 receive : 2 receive : 3 receive : 4 receive : 5 receive : 6 receive : 7 receive : 8 receive : 9 命令退出代码 0.
#主程序并未等待线程完成,就退出了,线程只执行了2次就没了。
package main import ( "fmt" ) var c chan int func send(i int) { fmt.Println("send -> ", i) c <- i } func receive() { fmt.Println("receive : ", <-c) } func main() { count := 10 c = make(chan int, 10) for i := 0; i < count; i++ { send(i) } for i := 0; i < count; i++ { go receive() } } //------输出---- E:/Go/bin/go.exe run goroutine.go [D:/Golang/Test/src] send -> 0 send -> 1 send -> 2 send -> 3 send -> 4 send -> 5 send -> 6 send -> 7 send -> 8 send -> 9 receive : 0 receive : 1 命令退出代码 0.