Go信道 | 青训营笔记

59 阅读2分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 11 天

声明和存取

channel,是一种带有类型的管道引用类型

使用前需要make(Type, (缓冲容量))

不带缓冲区的管道必须结合协程使用

可以查看长度len和容量cap

package mainimport "fmt"func main() {  // 声明一个string信道,容量为2  var ch chan string = make(chan string, 2)  ch <- "枫枫" // 写入数据到信道中  ch <- "知道"  s := <-ch // 从信道读取数据  fmt.Println(s)  ss, ok := <-ch  fmt.Println(ss, ok)  close(ch)}
存入:channel <- value取出:value, (ok) <- channel丢弃:<- channel先进先出,自动阻塞数据需要保持流动,否则会阻死报错

搭配协程使用

package mainimport "fmt"func pushNum(c chan int) {  for i := 0; i < 100; i++ {    c <- i  }  close(c) // 写完必须要关闭,不然会死锁}func main() {  var c1 chan int = make(chan int, 2) // 2表示缓冲区大小  go pushNum(c1)  for value := range c1 {    fmt.Println(value)  }}

多个协程函数,close就不能写在协程函数里了

package mainimport (  "fmt"  "sync")var ch chan int = make(chan int, 10)var wg = sync.WaitGroup{}func pushNum() {  for i := 0; i < 5; i++ {    ch <- i  }  wg.Done()}func main() {  wg.Add(2)  go pushNum()  go pushNum()  wg.Wait()  close(ch)  for {    res, ok := <-ch    if !ok {      break    }    fmt.Println(res)  }}

close

使用close之后就不能在继续写入了,但是还可以继续从缓冲区读取

  1. close之后,读取的chan是数据类型的默认值
  2. close之后,不能再往chan里面写入数据
  3. for range之前必须要close

可读可写

package mainimport "fmt"func main() {  var ch chan int = make(chan int, 2)  // 可读chan  var readCh <-chan int = ch  // 可写chan  var writeCh chan<- int = ch  writeCh <- 1  writeCh <- 2  fmt.Println(<-readCh)  fmt.Println(<-readCh)}

select … case

适用于无法确认合适关闭信道的情况

通常结合for循环使用

select … case会阻塞到某个分支可以继续执行时执行该分支,当没有可执行的分支是执行default分支

package mainimport "fmt"func main() {  var ch1 chan int = make(chan int, 2)  var ch2 chan int = make(chan int, 2)  var ch3 chan int = make(chan int, 2)  ch1 <- 1  ch2 <- 2  ch3 <- 3  select {  // 监听多个chan的情况,是随机执行  case v := <-ch1:    fmt.Println(v)  case v := <-ch2:    fmt.Println(v)  case v := <-ch3:    fmt.Println(v)  default:    fmt.Println("没有数据")  }}
package mainimport "fmt"func PrimeNum(n int, c chan int) {  for i := 2; i < n; i++ {    if n%i == 0 {      return    }  }  c <- n}func main() {  c := make(chan int)  for i := 2; i < 100001; i++ {    go PrimeNum(i, c)  }Print:  for {    select {    case v := <-c:      fmt.Printf("%v\t", v)    default:      fmt.Printf("所有素数都已被找到")      break Print    }  }}