GoLangStudy:day10
GOday10
golang语法基础(channel管道part1)
1.channel的基本定义与使用
示例:
package main
import "fmt"
func main() {
//定义一个无缓存channel,接收int类型的值
c := make(chan int)
go func() {
defer fmt.Println("goroutine 结束")
fmt.Println("goroutine正在运行")
c <- 666 //将666发送给c管道
}()
num := <-c //从c中接受数据并赋值给num
//<-c,意思是读取c管道中的值,然后抛弃掉
fmt.Println("num =", num)
fmt.Println("main goroutine 结束")
}
输出结果:
goroutine正在运行
goroutine 结束
num = 666
main goroutine 结束
channel可以将两个不同步的goroutine连接起来:
上面示例代码中,主协程和分协程的运行是不同步的,那么连接两个协程的关键语句就是主协程中的num := <-c和分协程中的c <- 666
1,当主协程运行到num := <-c而分协程没有运行到c <- 666时,主协程会发生阻塞,直到分协程运行到管道部分,阻塞才会解除
2,反之亦然,分协程先运行到管道部分的时候,分协程的阻塞也会发生,并在主协程运行到管道部分时解除
2.channel有缓冲与无缓冲同步问题
无缓冲channel:(与上文代码原理一致)

有缓冲channel:

在有缓冲情况下,若通道内存储满了,则发送方会发生阻塞,直到接收方取值为管道腾出空间
反之亦然,若通道内空了,则接收方会发生阻塞,直到发送方传入新的值
示例:
package main
import (
"fmt"
"time"
)
func main() {
//创建一个有缓存channel,容量为3
c := make(chan int, 3)
//len表示管道c中存储的数据个数,cap表示管道c的总容量
fmt.Println("len(c)=", len(c), ", cap(c)=", cap(c))
go func() {
defer fmt.Println("子协程结束")
for i := 0; i < 3; i++ {
c <- i
fmt.Println("子协程正在运行,发送的元素i=", i, "len(c)=", len(c), ", cap(c)=", cap(c))
}
}()
time.Sleep(2 * time.Second)
for i := 0; i < 3; i++ {
num := <-c //从c中接受数据,并赋值给num
fmt.Println("num=", num)
}
fmt.Println("main 结束")
}
输出结果:
len(c)= 0 , cap(c)= 3
子协程正在运行,发送的元素i= 0 len(c)= 1 , cap(c)= 3
子协程正在运行,发送的元素i= 1 len(c)= 2 , cap(c)= 3
子协程正在运行,发送的元素i= 2 len(c)= 3 , cap(c)= 3
子协程结束
num= 0
num= 1
num= 2
main 结束
3.channel的关闭特点
关闭channel示例:
package main
import (
"fmt"
)
func main() {
//创建一个无缓存channel
c := make(chan int)
go func() {
for i := 0; i < 5; i++ {
c <- i
}
//close是go的内嵌函数,可以关闭一个channel
close(c)
}()
for {
//if-else判断语句的简写方式
//先执行data, ok := <-c,随后对ok进行判断
if data, ok := <-c; ok {
fmt.Println(data)
} else {
break
}
}
fmt.Println("main 结束")
}
输出结果:
关闭channel:
0
1
2
3
4
main 结束
不关闭channel:(协程死锁,程序报错)
0
1
2
3
4
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan receive]:
main.main()
D:/GoStudyProjects/demo01/main.go:20 +0xbd
channel关闭时注意事项:

(nil channel一般不会实际使用)
浙公网安备 33010602011771号