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)

}

已经有一写一读,为什么还会死锁?怎么样才能不死锁呢?
...全文
77 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进程,去掉该行即可
内容概要:本文系统介绍了Go语言在高并发编程中的核心特性和实战应用。围绕Goroutine、Channel、Select和Context四大并发核心机制展开,详细阐述了其原理与使用方式,并结合生产者-消费者模型、并发文件处理、分布式任务调度和高并发Web服务器等实际场景,展示了Go语言在提升程序性能和资源利用率方面的强大能力。同时,文章还深入探讨了并发编程中常见的死锁、竞态条件和内存管理问题,提供了有效的规避策略和最佳实践,帮助开发者编写高效、安全、稳定的并发程序。; 适合人群:具备Go语言基础,有一定并发编程需求的开发人员,尤其是从事后端服务、分布式系统、云计算等相关领域的1-3年经验研发人员。; 使用场景及目标:①理解Go语言轻量级协程Goroutine与传统线程的区别及其调度机制;②掌握Channel在Goroutine间通信与同步中的应用;③学会使用Select实现多路复用和Context进行任务取消与超时控制;④在实际项目中构建高性能并发系统,如批量数据处理、任务调度平台、高并发API服务等; 阅读建议:此资源理论与实践结合紧密,建议读者在学习过程中动手编写并运行示例代码,深入理解并发机制的工作原理。同时应重点关注并发安全问题,结合调试工具分析竞态条件和死锁场景,逐步掌握构建健壮并发程序的能力。

476

社区成员

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

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