go channel
声明和存取 channel,是一种带有类型的管道引用类型 使用前需要make(Type, (缓冲容量)) 不带缓冲区的管道必须结合协程使用 可以查看长度len和容量cap package m
go channel
发布时间:2023-10-06 (2023-10-06)

声明和存取

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

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

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

可以查看长度len和容量cap

package main

import "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 main

import "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 main

import (
  "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 main

import "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 main

import "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 main

import "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
    }
  }

}