Golang Worker Pool无结果返回问题排查求助
问题分析与修复
你的代码出现了死锁,导致控制台没有任何输出,核心原因是results通道的缓冲限制和接收逻辑的阻塞问题:
- 死锁成因:
results通道的缓冲只有100,当100个worker都向通道发送了结果后,缓冲被填满- 后续worker执行
results <- ...时会被阻塞,无法继续处理ports通道里的剩余端口 - main函数的接收循环需要等待65535条结果才能结束,此时所有worker都卡在发送结果的操作上,main也卡在接收结果的操作上,形成循环阻塞
修复方案(使用WaitGroup优化)
下面是调整后的代码,通过sync.WaitGroup跟踪worker状态,配合异步接收结果的逻辑解决死锁:
package main import ( "fmt" "net" "sync" ) func worker(ports <-chan int, results chan<- string, wg *sync.WaitGroup) { defer wg.Done() // worker完成时标记WaitGroup计数减一 for p := range ports { address := fmt.Sprintf("127.0.0.1:%d", p) conn, err := net.Dial("tcp", address) if err != nil { results <- fmt.Sprintf("Port %d is closed: %s", p, err.Error()) } else { conn.Close() results <- fmt.Sprintf("Port %d is open", p) } } } func main() { ports := make(chan int, 100) results := make(chan string) // 改为无缓冲通道,避免缓冲限制问题 var wg sync.WaitGroup workerCount := cap(ports) wg.Add(workerCount) // 启动指定数量的worker for i := 0; i < workerCount; i++ { go worker(ports, results, &wg) } // 异步发送所有端口号,避免阻塞main go func() { for j := 1; j <= 65535; j++ { ports <- j } close(ports) // 端口发送完毕,关闭ports通道 wg.Wait() // 等待所有worker处理完所有端口 close(results) // 所有结果发送完毕,关闭results通道 }() // 遍历results通道,实时输出结果,直到通道关闭 for res := range results { fmt.Println(res) } }
关键修改点说明
sync.WaitGroup:用于跟踪所有worker的执行状态,确保所有端口处理完成后再关闭results通道- 异步发送端口:将端口发送逻辑放到单独的goroutine中,避免main被阻塞
- 无缓冲
results通道:配合实时接收的for range循环,避免缓冲满导致的worker阻塞 - 通道关闭时机:在所有worker处理完成后关闭
results,让main的接收循环自动终止
内容的提问来源于stack exchange,提问作者Aidan Ling
相关产品推荐
相关产品推荐

