Почему этот код не соответствует условиям гонки? - PullRequest
0 голосов
/ 08 мая 2019

У меня есть этот код 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()
}

Насколько я понимаю, когда-нибудь при записи в выходной файл он обязательно попадет в состояние состязания, но этого не произойдет.Я имею в виду, что я выполнял этот код бесчисленное количество раз, никогда не сталкиваясь с какими-либо проблемами.Он даже дает один и тот же результат каждый раз.

Почему это так?Я что-то упускаю?

ОБНОВЛЕНИЕ: Когда я говорю, что это связано с состоянием гонки, я имею в виду, что при запуске нескольких подпрограмм возможно, что более одной подпрограммы захочет записать в файлв то же время.

1 Ответ

2 голосов
/ 08 мая 2019

Когда я говорю, что он обязательно столкнется с состоянием гонки, я имею в виду, что при запуске нескольких процедур, более одной программы может захотеть записать в файл одновременно.

Нет проблем открыть файл несколько раз. А поскольку вы явно используете O_APPEND, записи не плохо взаимодействуют друг с другом. Цитировать от человек открыт :

O_APPEND ...
Перед каждой записью (2) смещение файла помещается в конец файла, как будто с lseek (2). Модификация смещения файла и операция записи выполняются как один атомарный шаг .

...