Go可组合goroutine管道使用scanner.Scan()读文件的同步问题
问题根源
判断正确,核心问题是文件关闭时机错误。readValuesFromFile函数启动标注(1)的goroutine后会立即返回,函数返回时触发外层的defer file.Close()执行,直接关闭了文件描述符。此时子goroutine中scanner.Scan()才开始读取已关闭的文件,自然无法读取到有效内容。
替换为直接写入随机字符串的场景下不需要操作文件描述符,所以不会受文件提前关闭的影响,流水线可以正常运行。
修复方案
最符合Go语言惯例的修复方式是将文件关闭逻辑移入子goroutine内部,确保所有文件读取操作完成后再释放文件资源:
func readValuesFromFile(filename string) <-chan string { file, err := os.Open(filename) if err != nil { log.Fatal(err) } inputStream := make(chan string) go func() { //(1) // defer移至此处,子goroutine执行完成前再关闭文件 defer file.Close() count := 0 scanner := bufio.NewScanner(file) for scanner.Scan() { // (2) inputStream <- strings.TrimSpace(scanner.Text()) count = count + 1 } // 补充 scanner 错误处理,避免读取出错无感知 if err := scanner.Err(); err != nil { log.Printf("文件读取异常: %v", err) } close(inputStream) }() return inputStream }
补充说明
当前流水线的整体调度逻辑没有问题:主goroutine会阻塞在writeResults函数内持续读取通道内容,直到通道被关闭才会退出,不会出现子goroutine未执行完成主进程就提前终止的情况。
内容的提问来源于stack exchange,提问作者DraQ
相关产品推荐
相关产品推荐

