为什么此代码未达到竞争条件?

时间:2019-05-08 10:28:10

标签: multithreading go race-condition goroutine

我有这个go代码,该代码遍历目录文件树,并在其中生成每个文件的MD5哈希值,并将结果写入输出文件中。

package main

import (
    "crypto/md5"
    "encoding/hex"
    "fmt"
    "io"
    "os"
    "path/filepath"
    "sync"
)

func main() {

    filePath := os.Args[1]
    output := os.Args[2]
    wg := &sync.WaitGroup{}

    err := filepath.Walk(filePath, func(path string, info os.FileInfo, err error) error {
        if !info.IsDir() {
            wg.Add(1)
            go func(path string) {
                md5Sum, _ := md5File(path)
                if err := writeToFile(path, md5Sum, output); err != nil {
                    panic(err)
                }
                wg.Done()
            }(path)
        }
        return nil
    })
    if err != nil {
        panic(err)
    }
    wg.Wait()
}

func md5File(filePath string) (string, error) {
    file, err := os.Open(filePath)
    if err != nil {
        return "", err
    }
    defer file.Close()

    hash := md5.New()
    if _, err := io.Copy(hash, file); err != nil {
        return "", err
    }

    checksum := hash.Sum(nil)

    return string(hex.EncodeToString(checksum)), nil
}

func writeToFile(filePath, md5sum, output string) error {

    file, err := os.OpenFile(output, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0755)
    if err != nil {
        return err
    }

    defer file.Close()

    file.WriteString(fmt.Sprintf("%s %s\n", md5sum, filePath))

    return file.Sync()
}

据我所知,它必然会在写入输出文件的某个时候陷入竞争状态,但绝不会。我的意思是我无数次执行了这段代码,从未遇到任何问题。甚至每次都会产生相同的结果。

那是为什么?我想念什么吗?

更新:当我说它必然会遇到竞争状况时,我的意思是在运行多个goroutine时,可能有多个goroutine希望同时写入文件。

1 个答案:

答案 0 :(得分:2)

  

当我说它必然会遇到竞争状况时,我的意思是说,当运行多个goroutine时,可能有多个goroutine希望同时写入文件。

多次打开文件不是问题。并且由于您显式使用O_APPEND,因此写入之间不会发生不良交互。引用  来自man open

  

O_APPEND ...
  在每次write(2)之前,文件偏移都位于文件的末尾,就像使用lseek(2)一样。 文件偏移量的修改和写操作是单个原子步骤