一、问题截图

fatal error: all goroutines are asleep - deadlock!

goroutine 1 [chan receive]:
main.main()
/Users/dianjiu/Codes/go/src/go-learn/demo03/demo.go:36 +0x164 goroutine 18 [chan receive]:
main.consumer(0x140001020c0, 0x14000102060)
/Users/dianjiu/Codes/go/src/go-learn/demo03/demo.go:10 +0x148
created by main.main
/Users/dianjiu/Codes/go/src/go-learn/demo03/demo.go:31 +0x104
exit status 2 [Done] exited with code=1 in 10.226 seconds

二、问题代码

package main

import (
"fmt"
"strconv"
"time"
) func consumer(data chan int, done chan bool) {
for x := range data {
// println("recv:", x)
i := strconv.Itoa(x)
fmt.Println(time.Now().Format("2006-01-02 15:04:05"), "调用客户端"+i+"结束")
// <-data
}
done <- true
} func producer(data chan int, done chan bool, i, len int) {
x := strconv.Itoa(i)
fmt.Println(time.Now().Format("2006-01-02 15:04:05"), "调用客户端"+x+"开始")
//单个客户端处理时间为10秒
time.Sleep(time.Second * 10)
data <- i
} func main() {
fmt.Println(time.Now().Format("2006-01-02 15:04:05"), "开始了")
done := make(chan bool)
data := make(chan int)
go consumer(data, done)
for i := 0; i < 5; i++ {
go producer(data, done, i, 5)
} <-done
}

三、问题原因

出现上面协程死锁的原因是生产方法只会在data channel中放五个数据,消费方法在消费完这五个数据后,还会一直等待data channel有新的数据输入,无法结束。这样的话 Go就会判定为死锁。

四、问题解决

为了解决这个问题,我们在生产完五个数据后对data channel进行关闭,这样消费方法就可以正常退出了。

五、具体实现

利用sync.WaitGroup解决,在所有的 data channel 的输入处理之前,wg.Wait()这个goroutine会处于等待状态。当生产方法处理完后(wg.Done),wg.Wait()就会放开执行,执行后面的close(results)。

注意:要把wg.Add(1)放到go producer()外面。如果放到里面的话,(for i := 0; i < 5; i++)里的go producer()有可能会在wg.wait的go func之后执行,这样close(results)就会先执行。

package main

import (
"fmt"
"strconv"
"sync"
"time"
) var wg sync.WaitGroup func consumer(data chan int, done chan bool) {
for x := range data {
i := strconv.Itoa(x)
fmt.Println(time.Now().Format("2006-01-02 15:04:05"), "调用客户端"+i+"结束")
}
done <- true
} func producer(data chan int, done chan bool, i, len int) {
x := strconv.Itoa(i)
fmt.Println(time.Now().Format("2006-01-02 15:04:05"), "调用客户端"+x+"开始")
//单个客户端处理时间为10秒
time.Sleep(time.Second * 10)
data <- i
defer wg.Done()
} func main() {
fmt.Println(time.Now().Format("2006-01-02 15:04:05"), "开始了")
done := make(chan bool)
data := make(chan int)
go func() {
wg.Wait()
close(data)
}()
go consumer(data, done)
for i := 0; i < 5; i++ {
wg.Add(1)
go producer(data, done, i, 5)
} <-done
}

六、问题总结

所有 goroutine 在 main() 函数结束时会一同结束。

最新文章

  1. 从 HTTP 到 HTTPS - 什么是 HTTPS
  2. recyleView使用笔记
  3. ERROR Cannot determine the location of the VS Common Tools Folder
  4. android 浏览器开发实例
  5. HQL查询语言的使用介绍
  6. hdu 4452
  7. [置顶] 创建GitHub技术博客全攻略
  8. SQL Server 中同时操作的例子:
  9. node.js基础:模块的创建和引入
  10. Struts(二十八):自定义拦截器
  11. python学习日记(OOP——@property)
  12. php使用select语句查询数据信息
  13. Elasticsearch 安全篇
  14. 应用 XAF 开发移动手机应用
  15. Oracle Ora 错误解决方案合集
  16. nodejs笔记之文件操作
  17. Java核心技术之基础知识
  18. 【Python】【Web.py】详细解读Python的web.py框架下的application.py模块
  19. Codeforces735A Ostap and Grasshopper 2016-12-13 11:53 78人阅读 评论(0) 收藏
  20. Remon Spekreijse CSerialPort用法

热门文章

  1. 【NX二次开发】Block UI 角度尺寸
  2. 【creo】CREO5.0+VS2019配置(还没写完)
  3. 谈谈fork/join实现原理
  4. UnityPlayerActivity删除后的后果
  5. 仅使用JsonUtility &amp;&amp; File类实现Json数据读写
  6. Cloudflare DDoS配置案例
  7. 04 jumpserver资产管理
  8. XML:xml常用注解
  9. Mybatis学习(6)与Spring MVC 的集成
  10. jenkins send files or publish