未将填充通道的函数调用嵌入 Goroutine 会导致死锁的原因是什么?
来源:stackoverflow
时间:2024-03-05 12:18:26 444浏览 收藏
目前golang学习网上已经有很多关于Golang的文章了,自己在初次阅读这些文章中,也见识到了很多学习思路;那么本文《未将填充通道的函数调用嵌入 Goroutine 会导致死锁的原因是什么?》,也希望能帮助到大家,如果阅读完后真的对你学习Golang有帮助,欢迎动动手指,评论留言并分享~
我知道 sync
包及其 waitgroup
选项,我不想将其用于此测试。我正在测试一种信号量。
所以我有:
package main import ( "fmt" "os" "time" ) func main() { fmt.print("wassap") jobs := make(chan int) processstarted := make(chan struct{}, 1) processcompleted := make(chan struct{}, 1) createjobs(jobs) go func() { worker(jobs, processstarted, processcompleted) }() go func() { sync(processstarted, processcompleted) }() time.sleep(3600 * time.second) fmt.print("\nend of main...") interrupt := make(chan os.signal) <-interrupt } func createjobs(jobs chan<- int) { defer close(jobs) for i := 1; i < 20; i++ { jobs <- i } } func worker(jobs <-chan int, processstarted <-chan struct{}, processcompleted <-chan struct{}) { for { select { case i := <-jobs: fmt.printf("\nfetching job #%d from channel", i) time.sleep(2 * time.second) case <-processstarted: fmt.print("\nprocess started. waiting for it to be completed") <-processcompleted fmt.print("\nprocess completed") } } } func sync(processstarted chan<- struct{}, processcompleted chan<- struct{}) { // acquire semaphore. send signal to channel to indicate that it is busy processstarted <- struct{}{} for i := 1; i < 5; i++ { fmt.printf("\nprocessing %d", i) time.sleep(5 * time.second) } // release semaphore processcompleted <- struct{}{} }
我想要测试的非常简单:我有一个 createjobs
函数,其唯一目的是将元素添加到通道,在本例中是一个 int 通道。然后我有一个 worker
将从该通道中提取对象并在提取下一个元素之前休眠 2 秒。
现在,还有同步功能。该函数的唯一目的是模拟 worker
运行时启动的进程。如果此进程处于活动状态,则在 sync
结束时应停止处理 jobs
元素,这就是为什么我有两个通道,一个表示进程已启动,另一个表示进程结束。
运行我的代码时出现以下错误:
fatal error: all goroutines are asleep - deadlock!
如果我修改 createjobs
的调用方式,将其包装在如下所示的 goroutine 中:
go func() { createJobs(jobs) }()
然后我的代码运行正确。
我只是想了解为什么会发生这种情况。我的意思是: main
例程正在执行,然后它调用 createjobs
(无换行),因此 main
例程应该被阻止,直到此调用结束。一旦 createjobs
结束,就说明通道中有元素了。 main
继续执行并启动其他 goroutine worker
和 sync
来完成它们的工作。在 main
结束之前,我只是添加一个睡眠程序,以便为之前创建的 goroutine 提供完成时间。
我不是在询问这个问题的其他解决方案,我只是想知道当 createjobs
发生在 goroutine 之外时会发生什么。
正确答案
您将 jobs
声明为无缓冲通道,然后尝试将 20 个值同步推入其中。当您调用 createjobs(jobs)
时,这将阻止您的主函数。
将第 13 行更改为:
jobs := make(chan int, 20)
...将解决僵局。
编辑 - 评论中要求的澄清:
无缓冲通道没有容量,并且会阻止生产者的执行,直到消费者收到消息为止。
无缓冲通道的一个很好的类比是管道,在本例中,过程如下所示:
+------------------+ +------------+ +-------------+ | PRODUCER | | PIPE | | CONSUMER | | +---->| +----->| | | createJobs(jobs) | | unbuffered | | worker(...) | | | | channel | | | +------------------+ +------------+ +-------------+
发生死锁是因为 createjobs(jobs)
被同步调用,并且还没有消费者在运行。
当在 goroutine 中调用函数(producer)时它可以工作,因为基本上插入通道和读取通道是并行发生的?
是的。如果生产者被异步调用,它不会阻塞 main()
函数,因此消费者也将有机会被调用。在这种情况下,生产者将一一推送其所有任务,就像工作人员一一消费它们一样。
以上就是《未将填充通道的函数调用嵌入 Goroutine 会导致死锁的原因是什么?》的详细内容,更多关于的资料请关注golang学习网公众号!
-
502 收藏
-
502 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
139 收藏
-
204 收藏
-
325 收藏
-
477 收藏
-
486 收藏
-
439 收藏
-
357 收藏
-
352 收藏
-
101 收藏
-
440 收藏
-
212 收藏
-
143 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 542次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 508次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 497次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 484次学习