请稍等 ...
×

采纳答案成功!

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

老师,您好!channel死锁的问题

图片描述
图片描述
截图中的代码:
forever:是一个无缓冲的通道

<- forever:没有任何goroutine向forever管道生产数据,一直阻塞中
或者
forever <- true:没有任何goroutine从forever管道读取数据,一直阻塞中

执行后,会一直循环打印555,并未出现deadlock死锁现象

学生的困惑如下:
正因为上述代码能正确执行,并没有出现deadlock死锁现象,反而让学生陷入了困惑

因为在学习channel这一章节时,学生私下总结了一条结论:goroutine的生产与消费都需要准备就绪,理解的白话文就是channel像是一个流水的管道,读取与写入都需要准备好,否则容易产生deadlock死锁现象,但上述代码却好像违背了这一结论,只有读或者只有写时,也没有出现deadlock死锁现象

请老师能指点一下,学生该如何正确理解channel呢?

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

2回答

慕妹3255656 2023-12-05 08:25:17

我也是想了很久才明白。

首先,老师说的没错,如果没有缓存的话,接受者如果没有准备就绪,,发送者就会被阻塞。但阻塞不一定是deadlock。

比如你在主线程里先往一个没有接受者的无缓冲channel里发送数据,那一定是死锁。因为没有缓存,那主线程执行到这里就被阻塞了,连启动接收者goroutine的机会都没有,就是死锁。但你只要不在主线程里这样写,写在子线程里,接收者和发送者谁先执行都完全没有关系,发送者一定是等到接收者启动才能往channel里写数据,因为是不在主线程,接收者和发送者的goroutine都被启动,所以不存在死锁。


缓存的作用是让发送者在向channel里发送数据时,直到buffer满之前不被阻塞。所以如果有缓存的channel,你在主线程里先往channel发送数据也是没问题的,因为不会被阻塞,底下的负责接受的线程或代码能有机会被执行。


至于有没有报错问题,deadlock是一个runtime错误,也就是执行之后才知道。这个可能和go版本有关,这段程序从理论上说就是死锁,因为forever <- true以后的代码没有机会执行。如果那个子协程不是无限循环的话,也会报runtime错误。


0 回复 有任何疑惑可以回复我~
  • bobby #1
    是的,go的channel就是希望在编译期间今早发现这些错误,所以才会提示死锁,是为了防止错误的使用channel,不过新版本的go这里的提示也在不断改进, 最后https://tiancaiamao.gitbooks.io/go-internals/content/zh/10.1.html 建议好好了解一下go的happen-before机制
    回复 有任何疑惑可以回复我~ 2023-12-07 10:01:08
bobby 2022-06-25 12:51:19

刚才我也试了一下发现也没有这个问题, 你的go的版本是多少,有可能新版本对这个问题进行了修改

0 回复 有任何疑惑可以回复我~
  • 提问者 慕斯0066757 #1
    老师,您好!
    go版本是1.17
    
    学生在构建channel这一章节知识点时,因为与自身总结的结论有些违背,所以在实际使用中有些束手束脚,老师是否能点拨一下?
    回复 有任何疑惑可以回复我~ 2022-06-25 15:07:19
  • bobby 回复 提问者 慕斯0066757 #2
    go本身有一些hanppens-before原则, https://tiancaiamao.gitbooks.io/go-internals/content/zh/10.1.html 你可以看看这里有详细说明,会说明channel你启动的时候的go本身的顺序保证
    回复 有任何疑惑可以回复我~ 2022-06-28 18:14:15
问题已解决,确定采纳
还有疑问,暂不采纳
意见反馈 帮助中心 APP下载
官方微信