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

使用Golang Mutex锁时文件写入不符合预期的问题排查

问题排查与修复方案

常见错误点及对应解决方法

1. Mutex未全局共享(核心问题)

如果每个worker goroutine都初始化了独立的sync.Mutex实例,锁完全起不到互斥作用——多个goroutine各自持有自己的锁,依然会同时写入文件,导致数据被覆盖。

修复方式:确保所有worker共享同一个Mutex实例,通过指针传递或全局变量(全局变量需注意初始化时机)。

2. 文件打开模式错误

如果在每个worker中使用os.Create()打开输出文件,该函数会截断已有文件(清空内容后写入),哪怕加了锁,后执行的goroutine打开文件时会清空之前的写入内容,最终只剩最后一条数据。

修复方式:使用os.OpenFile()指定正确的打开模式:

f, err := os.OpenFile("output.txt", os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0644)
if err != nil {
    log.Fatal(err)
}
defer f.Close()
  • os.O_APPEND:以追加模式写入
  • os.O_WRONLY:只写模式
  • os.O_CREATE:文件不存在时创建

3. 未等待所有goroutine执行完成

如果主程序启动goroutine后直接退出,会导致部分worker还没完成写入就被终止,最终输出数据不全。

修复方式:使用sync.WaitGroup等待所有worker结束:

var wg sync.WaitGroup
for i := 0; i < 10; i++ {
    wg.Add(1)
    go func(workerID int) {
        defer wg.Done()
        // worker逻辑
    }(i)
}
wg.Wait()

完整修正示例代码

package main

import (
    "encoding/json"
    "log"
    "os"
    "sync"
)

// 假设API响应结构体
type APIResponse struct {
    Data string `json:"data"`
}

func main() {
    var (
        mutex    sync.Mutex
        wg       sync.WaitGroup
        workerNum = 10
    )

    // 预打开输出文件(避免每个worker重复打开)
    outputFile, err := os.OpenFile("output.txt", os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0644)
    if err != nil {
        log.Fatalf("无法打开输出文件: %v", err)
    }
    defer outputFile.Close()

    for i := 0; i < workerNum; i++ {
        wg.Add(1)
        go func(workerID int) {
            defer wg.Done()

            // 模拟从JSON文件读取API响应
            jsonData := []byte(`{"data": "worker_` + string(rune(workerID+48)) + `_response"}`)
            var resp APIResponse
            if err := json.Unmarshal(jsonData, &resp); err != nil {
                log.Printf("worker %d: 解析JSON失败: %v", workerID, err)
                return
            }

            // 加锁保护文件写入
            mutex.Lock()
            defer mutex.Unlock()

            // 写入数据到文件
            if _, err := outputFile.WriteString(resp.Data + "\n"); err != nil {
                log.Printf("worker %d: 写入文件失败: %v", workerID, err)
            }
        }(i)
    }

    wg.Wait()
    log.Println("所有worker执行完成")
}

关键注意事项

  • 尽量提前打开输出文件,避免每个worker重复打开/关闭文件,减少IO开销和潜在问题。
  • Mutex的Lock()和Unlock()必须成对出现,使用defer mutex.Unlock()可以避免因panic导致锁无法释放。
  • 如果worker需要处理大量文件读取/写入,可将文件写入逻辑封装成独立函数,确保锁的作用域覆盖整个写入流程。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 18:12:24