goroutine死锁问题

weixin_38065217 2019-09-20 10:53:03
package main

import (
"fmt"
)

var complete chan string = make(chan string)

func printstring(i int) {
fmt.Println("打印这里", i)
complete <- "妥了"
}

func main() {

go printstring(1)
msg := <-complete
fmt.Println(msg)
printstring(2)

}

已经有一写一读,为什么还会死锁?怎么样才能不死锁呢?
...全文
52 17 打赏 收藏 转发到动态 举报
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
weixin_38102914 2019-09-20
  • 打赏
  • 举报
回复
把最后一行去掉就可以了,你的complete 是无缓冲通道 ,最后一行 printstring(2) 只有发送,没有接受,所以阻塞了
weixin_38110193 2019-09-20
  • 打赏
  • 举报
回复
这个看你怎么理解了。 所以我说的是似乎,并没有说就是。 按照正常的理解,既然是一个通道,当然是发送接收而已,没那么多复杂的。同一个协程,我发了再收,应该也说得通,逻辑不矛盾。但是实际就是不行,和常规理解不同。 你当然可以说GO就是这样规定的,必须一个协程发,另一个协程收,没毛病。但这确实是不大合乎常规的理解。并且,显然,这里看出,带缓冲区和不带缓冲区,都是通道,存在一个很大区别。不注意,很可能犯这个错误。 所以,这个例子看出,尽量用带缓冲区的channel,哪怕是长度是1的缓冲区,也更不容易出错。按照常规理解,长度是1的缓冲区,就是一次只能发一个,实际就是和不带缓冲区的意思一样,当然这个是常规理解。但GO就是不按常规理解来,这个也不是GO的错。但这样,似乎欠缺点什么,至少不够友好。
weixin_38115771 2019-09-20
  • 打赏
  • 举报
回复
楼主这个例子,提醒我们,以后尽量用长度为1的通道,来代替无缓冲区通道,实际两个通道的作用都相同,但前者的坑更少。
weixin_38116227 2019-09-20
  • 打赏
  • 举报
回复
问题这里锁死的根本原因就是缓存区满了啊。 缓存区为0,无法写入,满了。 那如果缓存区为1,结果写入了2个数据,一样满了,也会死锁啊。 所以你就算缓存区部位0,也不能解决问题,反而使得问题隐藏的更深,带来跟多的问题。 这个不光实在体现在chan上,实际socket之类的链接都会有同样的问题 随便搜索下,比如 http://wiki.jikexueyuan.com/project/java-socket/socket-tcp-deadlock.html http://www.voidcn.com/article/p-cbjwyyjf-btm.html
weixin_38116935 2019-09-20
  • 打赏
  • 举报
回复
这个不算错误吧
weixin_38120675 2019-09-20
  • 打赏
  • 举报
回复
你说的有道理 呵呵
weixin_38121538 2019-09-20
  • 打赏
  • 举报
回复
make(chan string)和make(chan string,1)是两个不同的概念,前者是缓冲区长度为0,1个都存不了,所以写入时会阻塞。后者是缓冲区长度为1,能存一个,所以后者不阻塞。
weixin_38125461 2019-09-20
  • 打赏
  • 举报
回复
“已经有一写一读,为什么还会死锁?怎么样才能不死锁呢?” 代码实现并没有一写一读。
weixin_38065454 2019-09-20
  • 打赏
  • 举报
回复
select了解一哈
weixin_38065494 2019-09-20
  • 打赏
  • 举报
回复
因为你没异步 所以你的读和写只能按顺序。
weixin_38066913 2019-09-20
  • 打赏
  • 举报
回复
你最后一行只有一个写,肯定死锁啊
weixin_38072110 2019-09-20
  • 打赏
  • 举报
回复
应该不会吧
weixin_38078903 2019-09-20
  • 打赏
  • 举报
回复
似乎你发现了GO的一个bug。 这样也会报错 complete <- "aaa1" msg := <-complete fmt.Println(msg) complete <- "aaa2" msg = <-complete fmt.Println(msg) 理论分析,不应该出现错误的。 同一个协程,先写再读,不应该报错的。 但是,实际运行,确实报这个错误。 难道channel必须在不同协程之间读写? 但是,channel加上缓冲区,var complete chan string = make(chan string,1),就不报错了。 似乎不带缓冲区的channel只支持不同协程之间读写? 期待高手来解答。
weixin_38085383 2019-09-20
  • 打赏
  • 举报
回复
不是只有写没有读的问题。后面加上读,也会报错。 似乎是不带缓冲区的channel,用法特殊,只支持不同协程之间读写。或者根本就是GO的一个bug。 make(chan string,1),就不会报错。 很怪异。
weixin_38091234 2019-09-20
  • 打赏
  • 举报
回复
正解
weixin_38091368 2019-09-20
  • 打赏
  • 举报
回复
缓冲区满了自然死锁啊,没看出有什么地方有bug.
weixin_38102527 2019-09-20
  • 打赏
  • 举报
回复
基础不扎实 概念: 无缓冲通道上的发送操作将会阻塞,直到另一个goroutine在对应通道上执行接收操作时,这时值传送完成,2个goroutine都可以执行 看懂了上面的话,就不难发现printstring(2)阻塞了main进程,去掉该行即可

435

社区成员

发帖
与我相关
我的任务
社区描述
其他技术讨论专区
其他 技术论坛(原bbs)
社区管理员
  • 其他技术讨论专区社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧