chan chan 构造导致死锁
我试图通过编写一小段代码来理解 Go 中的 chan chan
构造,如下所示,我希望 3 个工作子例程处理 10 个作业。每个工作子例程都有自己的通道,在其中接收要处理的“作业”。主 Go 例程通过从通道池中获取通道(因此是 chan chan
构造)来将作业分发到工作通道。
但是这段代码会导致死锁情况!我尝试了此代码的一些变体,但遇到了相同的错误。
是否是因为工作子例程永远等待从其通道读取作业?或者是由于其他原因(也许通道过早关闭等)?我对整个结构的理解显然遗漏了一些东西。
有人可以帮我理解这个问题以及如何解决它吗?
游乐场中的代码,并根据要求复制到下面。
package main import ( "fmt" "sync" ) type Job struct { ID int } func worker(id int, jobs <-chan Job, wg *sync.WaitGroup) { defer wg.Done() fmt.Printf("Worker %d starting\n", id) for job := range jobs { fmt.Printf("Worker %d processing job %d\n", id, job.ID) } fmt.Printf("Worker %d done\n", id) } func main() { numWorkers := 3 maxJobs := 10 var wg sync.WaitGroup // Create the pool of worker channels pool := make(chan chan Job, numWorkers) for i := 0; i < numWorkers; i++ { workerChan := make(chan Job) // Create a new channel for each worker pool <- workerChan // Add the worker channel to the pool go worker(i, workerChan, &wg) } defer close(pool) // Create jobs and distribute them to workers for i := 0; i < maxJobs; i++ { job := Job{ID: i} wg.Add(1) workerChan := <-pool workerChan <- job } // Wait for all workers to complete wg.Wait() fmt.Println("All jobs are processed") }
正确答案
首先:这里不需要一个频道的频道。要将工作分配给多个工作人员,您只需让所有工作人员从单个共享通道读取即可。当您向通道发送一件工作时,如果有可用的工作人员,其中一个将接收它,否则,通道发送操作将阻塞,直到有一个可用的工作人员为止。
如果您想为每个工作人员使用单独的通道,您仍然不需要通道的通道,您只需要其中的一部分即可。每个工作人员都将从专用渠道收听,您将自行管理工作分配:
numWorkers := 3 maxJobs := 10 var wg sync.WaitGroup pool := make([]chan Job, numWorkers) for i := 0; i < numWorkers; i++ { pool[i] = make(chan Job) wg.Add(1) go worker(i, pool[i], &wg) } for i := 0; i < maxJobs; i++ { job := Job{ID: i} pool[i%len(pool)] <- job } for _,c:=range pool { close(c) } wg.Wait()
您的代码有两个问题:
- 您应该在创建 Goroutine 时添加到等待组,而不是在将作业发送到通道时添加
- 当您从频道中读取频道时,该频道将从池中删除。所以当你读取3个通道后,
workerChannel := <-pool
将会阻塞,因为没有其他通道。如果你坚持使用频道的频道,你必须把它放回去:
workerChan := <-pool workerChan <- job pool<-workerChan
这样,您就可以将通道的通道用作循环队列
- 关闭
pool
不会有任何效果。您必须关闭pool
中的通道。
以上是chan chan 构造导致死锁的详细内容。更多信息请关注PHP中文网其他相关文章!

热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

AI Hentai Generator
免费生成ai无尽的。

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

本文解释了GO的软件包导入机制:命名imports(例如导入“ fmt”)和空白导入(例如导入_ fmt; fmt;)。 命名导入使包装内容可访问,而空白导入仅执行t

本文详细介绍了MySQL查询结果的有效转换为GO结构切片。 它强调使用数据库/SQL的扫描方法来最佳性能,避免手动解析。 使用DB标签和Robus的结构现场映射的最佳实践

本文解释了Beego的NewFlash()函数,用于Web应用程序中的页间数据传输。 它专注于使用newflash()在控制器之间显示临时消息(成功,错误,警告),并利用会话机制。 Lima

本文演示了创建模拟和存根进行单元测试。 它强调使用接口,提供模拟实现的示例,并讨论最佳实践,例如保持模拟集中并使用断言库。 文章

本文探讨了GO的仿制药自定义类型约束。 它详细介绍了界面如何定义通用功能的最低类型要求,从而改善了类型的安全性和代码可重复使用性。 本文还讨论了局限性和最佳实践

本文详细介绍了在GO中详细介绍有效的文件,将OS.WriteFile(适用于小文件)与OS.openfile和缓冲写入(最佳大型文件)进行比较。 它强调了使用延迟并检查特定错误的可靠错误处理。

本文使用跟踪工具探讨了GO应用程序执行流。 它讨论了手册和自动仪器技术,比较诸如Jaeger,Zipkin和Opentelemetry之类的工具,并突出显示有效的数据可视化
