【发布时间】:2019-05-08 10:28:09
【问题描述】:
我有这个 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 想要同时写入文件。 p>
【问题讨论】:
-
“根据我的理解,它一定会在某个时候遇到竞争条件......” - 您能否更详细地解释您的理解,即您在哪里看到比赛条件应该在什么情况下发生,如果比赛发生,结果应该如何?到目前为止,您只是期待一场比赛而不告诉任何细节,然后期待其他人解释为什么您没有解释的事情没有发生。
-
@SteffenUllrich 我已经为问题添加了更多细节。
-
必须注意:并非所有文件系统都与 POSIX 兼容。最好是同步/序列化对文件的写入(附加)。每次都打开/关闭它是一种浪费。打开它一次,然后在你处理完所有文件的地方关闭它。
-
@icza 我明白了。我故意想强制一个竞争条件只是为了测试。
标签: multithreading go race-condition goroutine