在 goroutine 中使用 io.Copy 时锁定

Lock when using io.Copy in a goroutine

我有一个包含大量“FileMetadata”结构的切片 (filesMeta)。我还有另一个切片(候选)包含其中一些结构的索引。我想做的是修改 filesMeta 切片以添加 md5 哈希,但仅针对索引在候选切片中的元素。

我正在使用 goroutines 来并行化工作,但 io.Copy 部分导致锁定,我不明白为什么。

这是代码:

for i := range candidates{
    wg.Add(1)
    go func(i int) {
        defer wg.Done()
        filesMeta[candidates[i]].Hash = md5Hash(filesMeta[candidates[i]].FullPath)
    }(i)
}
wg.Wait()


func md5Hash(filePath string) string {
    file, err := os.Open(filePath)
    if err != nil { 
        panic(err) 
    }
    defer file.Close()

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

    return hex.EncodeToString(hashInBytes)
}

谢谢!

编辑: 更详细一点,当被散列的文件在我的 SSD 中时它不会锁定,但当文件在文件共享上时它会锁定。

Edit2: 我注意到我忘了传递 wg,代码现在看起来像这样(仍然出现同样的错误):

for i := range candidates{
    wg.Add(1)
    go func(i int, wg *sync.WaitGroup) {
        defer wg.Done()
        filesMeta[candidates[i]].Hash = md5Hash(filesMeta[candidates[i]].FullPath)
    }(i, &wg)
}
wg.Wait()


func md5Hash(filePath string) string {
    file, err := os.Open(filePath)
    if err != nil { 
        panic(err) 
    }
    defer file.Close()

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

    return hex.EncodeToString(hashInBytes)
}

从外部存储读取时,尤其是通过网络读取时,读取可能会挂起。我建议当您通过网络驱动器读取文件时,一次只读取一个。我知道这会破坏并行化能力,但我们不能假装网络驱动器具有与本地驱动器相同的可靠性。

编辑 我提出上面的解决方案是因为有很多网络参数会影响网络存储设备的性能,例如:流量,传输速度等。我记得有一次我使用了一个驱动器通过网络存储 Unity 项目。有一天 Windows Explorer 开始崩溃,因为 Unity 使用了太多文件。我相信他们不是数百万。基于此,我认为由于 goroutine 数量众多,这种情况不太可能发生。我建议一次处理 1 个文件,考虑到文件可能很大(超过 50 GB)的情况,这可能会导致与网络存储提供商的通信崩溃。

MarcoLucidi 是对的,我一次打开了太多文件。我限制了并发 goroutines 的数量,现在它工作正常。