channel通道笔记

channel通道笔记


介绍

  • 语法
    • 1.一般使用make创建channel(常用)
      • c := make(chan datatype),datatype是数据类型
    • 2.直接显示声明,创建的值为空,一般没有太大意义
      • var c chan datatype
  • 三种定义写法:
    • 既可以收数据又可以发数据:chan datatype
    • 只可以收数据:chan <- datatype
    • 只可以发数据:<- chan datatype
  • 用法
    • 将数据发送到通道:channel变量 <- 数据,eg:c <- 10
    • 将通道数据发出:接收变量名:= <- channel变量 ,egdata := <- c
    • 将数据丢掉:<- channel变量,不接收数据
  • 注意
    • 通道一次只能接收一次数据,等到通道内部数据被接收后,再接收下一个数据
  • 类型
    • 介绍:通道分为有缓冲无缓冲的通道,Go提供内置函数lencap,无缓冲的通道的lencap都是0,有缓冲的len表示没有被读取的元素数,cap代表整个通道的容量
    • 作用
      • 无缓冲:通信和两个goroutine的同步(没有缓冲,一旦接收就要有人来收数据不然就报错)
      • 有缓冲:主要通信(因为有缓冲所以可以保存数据,意义是一接收到数据可以没有人收(不报错))
    • 语法:
      • 无缓冲:make(chan datatype)
      • 有缓冲:make(chan datatype,len),创建缓冲为len的通道
  • 实现goroutine之间的同步等待
    • 代码实现
    func main() {
          /创建无缓冲通道
          c := make(chan struct{})
          //通道要做的事情
          go func(i chan struct{}) {
      	    sum := 0
      	    for i := 0; i < 10000; i++ {
      		    sum += i
      	    }
      	    println(sum)
      	    //数据写进通道
      	    c <- struct{}{}
          }(c)
          println(runtime.NumGoroutine())
          //读通道c,通过通道进行同步等待
          <-c//丢掉数据
      }
    
    写到缓冲通道的数据不会消失,加上这一点我们可以实现用无缓冲同步goroutines,用有缓冲存储数据
    • 代码演示
    func main() {
          c := make(chan struct{})
          ci := make(chan int, 100)
          go func(i chan struct{}, j chan int) {
              for i := 0; i < 10; i++ {
                  ci <- i
              }
              close(ci)
              //写通道
              c <- struct{}{}
          }(c, ci)
          fmt.Printf("----------\n")
          println(runtime.NumGoroutine())
          //读通道c,通过通道进行同步等待
          <-c
          //此时ci通道已经关闭,匿名函数启动的goroutine已经退出
          fmt.Printf("----------\n")
          println(runtime.NumGoroutine())
          //但通道ci还可以继续读取
          fmt.Printf("----------\n")
          for v := range ci {
              println(v)
          }
      }
    
    详细解读:
    1.创建两个通道 c 和 ci,其中 c 是一个无缓冲通道,用于协程的同步等待;ci 是一个带有缓冲区大小为 100 的通道,用于向协程传递整数。
    2.启动一个匿名函数作为一个新的协程,并将 c 和 ci 作为参数传递给它。
    3.协程中的 for 循环会向 ci 通道中写入 0 到 9 的整数,然后通过调用 close(ci) 来关闭通道。
    4.在协程的最后,向 c 通道写入一个空结构体,以通知主协程协程已经完成。
    5.在主协程中,调用 runtime.NumGoroutine() 打印当前的 goroutine 数量,此时应该只有主协程和一个新的协程。
    6.等待协程完成,通过 <-c 读取 c 通道中的值,阻塞主协程,直到协程完成。
    7.执行 runtime.NumGoroutine(),此时应该只有主协程,新的协程已经退出。
    8.使用 for v := range ci 循环读取 ci 通道中的值,由于通道已经关闭,因此循环会在所有值都被读取后结束。
    9.在循环中,使用 println(v) 打印从 ci 通道中读取的每个整数。
  • 补充
    • 接收通道数据
      • 1.使用range接收:for v := range ci{}//ci为通道数据
      • 2.使用if value,ok := ci,通过判断ok来判断数据是否结束
  • 操作不同状态触发的三种行为
    • 触发panic
      • 1.向已经关闭的通道写入数据(关闭通道应该由写入者关闭)
      • 2.重复关闭的通道
    • 阻塞
      • 1.向未初始化的通道写入数据或读取数据导致当前goroutine永久阻塞
      • 2.向缓冲区已满的通道写入数据会导致goroutine阻塞
      • 3.通道中没有数据,读取该通道会导致goroutine阻塞
    • 非阻塞
      • 1.读取已经关闭的通道不会引发阻塞,而是立即返回通道元素类型的零值
      • 2.向有缓冲且没有满的通道读/写不会引发阻塞

2.利用循环取有缓存的通道数据

  • 取数据需要用for range
  • 取数据前需要将通道关闭: close(channel)
  • 如果用for循环取数据,不能写成for i:=0;i<len(channel);i++,因为len的大小会随着去除数据而变小,解决方案: 提前用num保存channel的最初数量

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我不吃牛肉!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值