如何在不使用锁的情况下等待goroutine完成并读取channel?
嘿,我瞅了下你的代码,发现几个关键问题导致它没按预期运行,咱们一个个拆解修复:
1. WaitGroup传递方式错了,导致永远阻塞
你现在把sync.WaitGroup直接作为参数传给readFile函数,但Go里函数参数是值传递——这意味着每个goroutine拿到的都是wg的副本。你在副本上调用wg.Done(),完全不会影响主goroutine里的那个wg实例,结果就是wg.Wait()会一直卡着,通道ch永远不会关闭,printer函数也会一直等着收数据,程序直接卡死。
修复方法:把函数参数改成指针类型,调用时传wg的地址,同时在readFile里用defer wg.Done()确保不管函数怎么退出都能标记任务完成:
// 修改函数定义为指针参数 func readFile(name string, ch chan string, wg *sync.WaitGroup) { defer wg.Done() // 必须加defer,放在函数开头最稳妥 // ... 其他代码 } // 调用时传地址 go readFile("A", ch, &wg) go readFile("B", ch, &wg)
2. 错误处理不完整+文件资源泄漏
- 你用
fmt.Errorf创建了错误,但既没打印也没返回,出错了你根本看不到任何提示,相当于白处理了。换成fmt.Printf或者log.Printf把错误输出出来。 - 打开文件后没有
defer file.Close(),这会导致文件句柄泄漏,程序运行时间越长,资源浪费越严重。
修复后的这部分代码:
file, err := os.Open(name) if err != nil { fmt.Printf("无法读取文件 %s: %s\n", name, err) return // 出错直接返回,别继续执行后面的代码 } defer file.Close() // 确保文件最终被关闭,放在err判断之后避免空指针
3. 补充:Scanner读取逻辑的完善
你代码里scanner := bufio.NewScanner(file)后面没写完,记得循环读取内容并发送到通道里,还要检查Scanner自身的错误:
scanner := bufio.NewScanner(file) for scanner.Scan() { ch <- scanner.Text() // 把每行内容发送到通道 } // 检查Scanner的错误(比如读取时的IO错误) if err := scanner.Err(); err != nil { fmt.Printf("扫描文件 %s 出错: %s\n", name, err) }
修复后的完整代码
package main import ( "bufio" "fmt" "os" "sync" ) func main() { ch := make(chan string) var wg sync.WaitGroup wg.Add(2) go readFile("A", ch, &wg) go readFile("B", ch, &wg) go func() { wg.Wait() close(ch) }() printer(ch) } func readFile(name string, ch chan string, wg *sync.WaitGroup) { defer wg.Done() file, err := os.Open(name) if err != nil { fmt.Printf("无法读取文件 %s: %s\n", name, err) return } defer file.Close() scanner := bufio.NewScanner(file) for scanner.Scan() { ch <- scanner.Text() } if err := scanner.Err(); err != nil { fmt.Printf("扫描文件 %s 出错: %s\n", name, err) } } func printer(ch chan string) { for line := range ch { fmt.Println(line) } }
内容的提问来源于stack exchange,提问作者konart
相关产品推荐
相关产品推荐

