本教材由知了传课辛苦制作而成,仅供学习使用,请勿用于商业用途!如进行转载请务必注明出处!谢谢!

channel

goroutine之间数据通信的桥梁

一、创建chan

1.无缓存的chan

// 1.使用内置的make ch1 := make(chan int) var ch2 chan int // 2.声明只读通道 ch2 := make(<-chan string) var ch3 <- chan int // 3.声明只写通道 ch3 := make(chan<- string) var ch2 chan <- int

注意:如果没有指定是写通道还是读通道,默认的就是双向的,可读可写

把数据往通道中发送时,如果接收方一直都没有接收,那么发送操作将持续阻塞。

2.有缓存的chan

ch1 := make(chan int, capacity) capacity:容量 当capacity=0时,channel是无缓冲阻塞读写的, 当capacity>0时,channel有缓冲,是非阻塞的,直到写满capacity个元素才阻塞写入 ch2 := make(chan int) 相当于ch2 := make(chan int, 0) ,capacity为0 // 声明带10个缓冲的通道 ch3 := make(chan string, 10)

注意:

  • 如果定义了缓存的大小,写入的大于了就会报错
  • 通过 len 函数可以获得 chan 中的元素个数,通过 cap 函数可以得到 channel 的缓存长度

fatal error: all goroutines are asleep - deadlock!

  • 当缓存满时,发送消息将阻塞
  • 当 channel 为空时,读取操作会造成阻塞

3.有缓存和无缓存的区别

  • 无缓存的chan,chan为空,读取将阻塞,chan不为空,写入将阻塞 (只能有一个)
  • 有缓存的chan,当缓存满了写入将阻塞,当chan为空读取将阻塞

二、关闭通道

ch := make(chan int) defer close(ch)

注意:

  • 关闭一个未初始化的 channel 会产生 panic
var ch chan int defer close(ch) panic: close of nil channel 此时的channil,未初始化 ch := make(chan int)就没问题,会分配内存
  • 重复关闭同一个 channel 会产生 panic
ch := make(chan int) defer close(ch) defer close(ch) panic: close of closed channel 已经关闭的了chan,不能再次关闭
  • 已关闭的chan中不能写入数据,
ch := make(chan int) defer close(ch) ch <- 3 fatal error: all goroutines are asleep - deadlock!
  • 从已关闭的 channel 读取消息不会产生 panic,且能读出 channel 中还未被读取的消息
  • 关闭 channel 会产生一个广播机制,所有向 channel 读取消息的 goroutine 都会收到消息
ch := make(chan int, 3) ch <- 1 ch <- 2 ch <- 3 close(ch) for x := range ch { fmt.Println(x) } x, ok := <- ch fmt.Println(x, ok) 注意:这里不能用defer close,会报错 fatal error: all goroutines are asleep - deadlock! defer 是在程序最后执行的,还没有关闭,就绪从goroutine中读取,肯定是不行的

二、goroutine使用chan通信

channel 一定要初始化后才能进行读写操作,否则会永久阻塞

1.写入

ch := make(chan int, 10) ch <- 3 ch <- 4 ch <- 5 缓存已满,继续写入会报错

2.读取

ch := make(chan int, 10) ch <- 3 ch <- 4 ch <- 5 // 一个一个读取,直到读取完 fmt.Println(<- ch) fmt.Println(<- ch) fmt.Println(<- ch) // 再继续读取回报错:fatal error: all goroutines are asleep - deadlock!

3.goroutine通信

猫主子和铲屎官的日常:

package main import ( "fmt" "sync" ) // 猫主子和铲屎官日常 var Wg = sync.WaitGroup{} func Cat(ch chan string){ foot,ok := <- ch fmt.Println(ok) if ok { fmt.Printf("猫主子吃了%s\n",foot) }else { fmt.Printf("铲屎官该投食了") } Wg.Done() } func Man(ch chan string,foot string) { ch <- foot fmt.Printf("铲屎官投食了%s\n",foot) Wg.Done() } func main() { foot := "罐头" ch := make(chan string,10) defer close(ch) go Man(ch,foot) for i:=0; i<10;i++ { Wg.Add(2) go Cat(ch) go Man(ch,foot) } Wg.Wait() }

1352人已阅读,今天你学习了吗?

添加新回复