You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在不使用锁的情况下等待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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 08:59:37