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

Go项目并发写入异常:程序提前退出,Goroutine未正常工作

问题分析与解决方案

这问题我之前做批量文件写入时也踩过一模一样的坑!核心原因是你的主goroutine没等所有负责写文件的子goroutine执行完就直接退出了——Go程序只要主goroutine结束,不管其他子goroutine有没有完成任务,都会直接终止整个进程。这就导致部分子goroutine还没来得及把内容写入文件,甚至连defer file.Close()都没执行,自然会出现文件已创建但内容为空的情况。

另外还有个容易忽略的细节:你直接把循环里的variable和values传给goroutine的话,因为Go循环变量是复用的,多个goroutine可能会拿到同一个变量的最终值,导致写入的内容和预期不符(不过你说串行正常、并发时是空文件,这个可能不是本次的主要问题,但还是要一起修正)。

修复步骤

我们可以用sync.WaitGroup来实现goroutine之间的同步,确保所有写入操作都完成后,主程序再退出:

  • 引入sync包,声明一个WaitGroup实例
  • 启动每个写文件goroutine前,调用wg.Add(1)标记有一个任务待完成
  • 在goroutine内部,用defer wg.Done()标记任务完成
  • 所有goroutine启动后,调用wg.Wait()等待全部任务结束

修改后的代码示例

主函数部分:

import "sync"

// ... 其他业务代码 ...

var wg sync.WaitGroup
for variable, values := range varValMap {
    wg.Add(1)
    // 用匿名函数捕获循环变量的副本,避免goroutine拿到过期值
    go func(v string, vals []string) {
        defer wg.Done()
        writeCsv(v, vals)
    }(variable, values)
}
// 等待所有写文件goroutine完成后再继续
wg.Wait()

writeCsv函数可保持不变:

func writeCsv(variable string, values []string) {
    fName := variable + ".csv"
    fPath := filepath.Join(xmlFolder, "_varval", fName)
    file, err := os.Create(fPath)
    check(err)
    defer file.Close()
    for _, value := range values {
        fmt.Fprintf(file, value + "\n")
    }
}

为什么串行执行正常?

因为串行时,主goroutine会逐个执行writeCsv函数,每个函数都完整执行完(包括文件写入、关闭)才会进入下一次循环,整个程序只有所有文件都写完才会退出,自然不会出现内容丢失的情况。

内容的提问来源于stack exchange,提问作者Milos Grujic

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 07:48:37