请稍等 ...
×

采纳答案成功!

向帮助你的同学说点啥吧!感谢那些助人为乐的人

老师,您好!关于channel的困惑,望老师指点迷津

图片描述

老师,您好!
在学习channel这一章节时,学生记住了一条结论:goroutine的生产与消费都需要准备就绪,理解的白话文就是channel像是一个流水的管道,进与出都需要准备好,否则容易产生死锁deadlock。

但在学生后续的练习与思考中,如上面截图的代码
forever:是一个无缓冲的通道
<- forever:没有任何goroutine向管道生产数据,一直阻塞中
但结果上述代码并没有出现死锁deadlock的现象,一直循环打印555

这个现象的产生好像与学生记住的结论有些违背,因此产生了困惑,只有消费,没有生产,也没有产生死锁deadlock,好像学生总结的结论并不是正确的

难道go程序认为我开启了一个goroutine,会有机会向forever生产数据吗?

正在回答 回答被采纳积分+3

2回答

城中城 2022-06-24 09:26:10

第一  只有存值  和 只有取值也是会存在死锁

如下列代码

package main

import (
   "fmt"
   "time"
)

func main() {
   // 有缓存 和 无缓冲最大的区别在于
   // 有缓存 可以在 协程未开启前 提前存放一个数据进去
   forever := make(chan bool) // 创建 channel       这个 是无缓冲通道
   //forever := make(chan bool, 1) // 这个是 有缓冲通道

   <-forever // 这里 你取出 channel 中的值     但是因为你没存值 导致 主协程 没有结束  一直阻塞在这里
   
   go func() { // 开启协程    在主协程 没死亡前   不会停止运行
      for {
         fmt.Println("555")
         time.Sleep(time.Second)
         //forever <- true  # 这个 打开这个注释 当你存入 值后 <-forever 就会接受到值 继续往下走
      }
   }()
   
   fmt.Println("777")
}

为什么这下就有 死锁现象呢 

之前就没有呢   跟你的 开启的子协程有关

因为你 创建的是无缓冲通道   导致执行到此行的时候

<-forever

 主协程是必须 阻塞在这里 等待其他协程需要 存储这个值

但是 因为 整个代码 运行到这里的时候 没创建任何一个 子协程  导致 这 行 

<-forever

注定没办法 解锁  死锁就产生了 


那么为什么 只是简单 把 这行放在 执行子协程 代码 前面 就有问题了呢

是因为 当前只有一个 协程  你把这个协程上锁了  所有协程都是睡眠状态 不就 死锁了啊


将 这个含代码放在 执行 子协程后面为什么没有问题呢

<-forever

是因为 当前有二个线程 你只是把主协程 上锁了   不是所有协程都是睡眠状态  所有可以流畅运行


你可以试一试这个

package main

import (
   "fmt"
   "time"
)

func main() {
   // 有缓存 和 无缓冲最大的区别在于
   // 有缓存 可以在 协程未开启前 提前存放一个数据进去
   forever := make(chan bool) // 创建 channel       这个 是无缓冲通道
   //forever := make(chan bool, 1) // 这个是 有缓冲通道

   go func() { // 开启协程    在主协程 没死亡前   不会停止运行
      for {
         forever <- true
         fmt.Println("555")
         time.Sleep(time.Second)
         //forever <- true  # 这个 打开这个注释 当你存入 值后 <-forever 就会接受到值 继续往下走
      }
   }()

   forever <- true // 这里 你取出 channel 中的值     但是因为你没存值 导致 主协程 没有结束  一直阻塞在这里
   fmt.Println("777")
}

请问有没有解开你心中的疑虑呢


1 回复 有任何疑惑可以回复我~
  • bobby #1
    这么长的回复很用心了
    回复 有任何疑惑可以回复我~ 2022-06-25 11:28:55
城中城 2022-06-24 00:25:49

我看起来 代码没有任何问题

我注释一下你的代码

package main

import "fmt"

func main() {
   // 有缓存 和 无缓冲最大的区别在于
   // 有缓存 可以在 协程未开启前 提前存放一个数据进去
   forever := make(chan bool) // 创建 channel       这个 是无缓冲通道
   //forever := make(chan bool, 1) // 这个是 有缓冲通道

   go func() { // 开启协程    在主协程 没死亡前   不会停止运行
      for {
         fmt.Println("555")
         //forever <- true  # 这个 打开这个注释 当你存入 值后 <-forever 就会接受到值 继续往下走
      }
   }()

   <-forever // 这里 你取出 channel 中的值     但是因为你没存值 导致 主协程 没有结束  一直阻塞在这里
   fmt.Println("777")
}


0 回复 有任何疑惑可以回复我~
  • 提问者 慕斯0066757 #1
    虽然没有得到我想要的答案,但还是非常感谢您。
    其实,我知道代码没有问题,正因为没有问题,我才产生的困惑,因为很多资料在说channel时,一直是以读取和写入同时准备就绪,但我真正想问的是:为什么上述代码中,只有读或者只有写时,为什么没有出现死锁现象?
    回复 有任何疑惑可以回复我~ 2022-06-24 08:15:45
问题已解决,确定采纳
还有疑问,暂不采纳
意见反馈 帮助中心 APP下载
官方微信