简单程序死锁,无法查明原因
Deadlock on simple program, can't identify the reason
我在以下代码中遇到死锁错误,但我无法确定原因。
该代码的目标是递归地获取给定文件夹中所有文件的 sha256 哈希值。 (最终目的是基于hash去除重复文件,作为学习项目)
为此,它生成一个 goroutine,该 goroutine 为每个文件生成另一个 goroutine 以获取哈希。哈希存储在通道中,并在代码末尾以简单循环读取。
根据打印件,检查所有文件,wg.Add 和完成似乎在正确的位置。
代码:
package main
import (
"crypto/sha256"
"fmt"
"io"
"io/fs"
"log"
"os"
"path/filepath"
"sync"
"time"
)
func get_fsha256sum(filepath string) string {
f, err := os.Open(filepath)
if err != nil {
log.Fatal(err)
}
defer f.Close()
return get_sha256sum(f)
}
func get_sha256sum(r io.Reader) string {
h := sha256.New()
if _, err := io.Copy(h, r); err != nil {
log.Fatal(err)
}
return fmt.Sprintf("%x", h.Sum(nil))
}
func main() {
start := time.Now()
ch := make(chan string, 10000)
var wg sync.WaitGroup
var get_fsha256sum_wrap = func(filepath string) {
start := time.Now()
ch <- get_fsha256sum(filepath)
fmt.Printf("%f-%s\n", filepath, time.Since(start))
wg.Done()
}
var walk_func = func(filepath string, info fs.DirEntry, err error) error {
wg.Add(1)
if err != nil {
return err
}
if info.IsDir() {
return nil
}
go get_fsha256sum_wrap(filepath)
return nil
}
var over_wrap = func(root string) {
filepath.WalkDir(root, walk_func)
wg.Wait()
close(ch)
}
go over_wrap("/run/media/user/Red/pictures_master/2021/01")
for v := range ch {
fmt.Println(v)
}
fmt.Printf("%s", time.Since(start))
}
错误信息:
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan receive]:
main.main()
/home/user/go_phockup/main.go:66 +0x273
goroutine 18 [semacquire]:
sync.runtime_Semacquire(0xc0000b8018)
/usr/local/go/src/runtime/sema.go:56 +0x45
sync.(*WaitGroup).Wait(0xc0000b8010)
/usr/local/go/src/sync/waitgroup.go:130 +0x65
main.main.func3(0x4e3d3f, 0x2b)
/home/go_phockup/main.go:62 +0x5e
created by main.main
/home/user/go_phockup/main.go:65 +0x1bd
exit status 2
知道哪里出了问题吗?
您的等待组正在等待的 goroutine 数量超过了您创建的数量。 walk_func 添加到 wg
,但可能 return 没有创建新的 goroutine。替换为:
var walk_func = func(filepath string, info fs.DirEntry, err error) error{
if err != nil {
return err
}
if info.IsDir() {
return nil
}
wg.Add(1)
go get_fsha256sum_wrap(filepath)
return nil
}
我在以下代码中遇到死锁错误,但我无法确定原因。 该代码的目标是递归地获取给定文件夹中所有文件的 sha256 哈希值。 (最终目的是基于hash去除重复文件,作为学习项目)
为此,它生成一个 goroutine,该 goroutine 为每个文件生成另一个 goroutine 以获取哈希。哈希存储在通道中,并在代码末尾以简单循环读取。
根据打印件,检查所有文件,wg.Add 和完成似乎在正确的位置。
代码:
package main
import (
"crypto/sha256"
"fmt"
"io"
"io/fs"
"log"
"os"
"path/filepath"
"sync"
"time"
)
func get_fsha256sum(filepath string) string {
f, err := os.Open(filepath)
if err != nil {
log.Fatal(err)
}
defer f.Close()
return get_sha256sum(f)
}
func get_sha256sum(r io.Reader) string {
h := sha256.New()
if _, err := io.Copy(h, r); err != nil {
log.Fatal(err)
}
return fmt.Sprintf("%x", h.Sum(nil))
}
func main() {
start := time.Now()
ch := make(chan string, 10000)
var wg sync.WaitGroup
var get_fsha256sum_wrap = func(filepath string) {
start := time.Now()
ch <- get_fsha256sum(filepath)
fmt.Printf("%f-%s\n", filepath, time.Since(start))
wg.Done()
}
var walk_func = func(filepath string, info fs.DirEntry, err error) error {
wg.Add(1)
if err != nil {
return err
}
if info.IsDir() {
return nil
}
go get_fsha256sum_wrap(filepath)
return nil
}
var over_wrap = func(root string) {
filepath.WalkDir(root, walk_func)
wg.Wait()
close(ch)
}
go over_wrap("/run/media/user/Red/pictures_master/2021/01")
for v := range ch {
fmt.Println(v)
}
fmt.Printf("%s", time.Since(start))
}
错误信息:
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan receive]:
main.main()
/home/user/go_phockup/main.go:66 +0x273
goroutine 18 [semacquire]:
sync.runtime_Semacquire(0xc0000b8018)
/usr/local/go/src/runtime/sema.go:56 +0x45
sync.(*WaitGroup).Wait(0xc0000b8010)
/usr/local/go/src/sync/waitgroup.go:130 +0x65
main.main.func3(0x4e3d3f, 0x2b)
/home/go_phockup/main.go:62 +0x5e
created by main.main
/home/user/go_phockup/main.go:65 +0x1bd
exit status 2
知道哪里出了问题吗?
您的等待组正在等待的 goroutine 数量超过了您创建的数量。 walk_func 添加到 wg
,但可能 return 没有创建新的 goroutine。替换为:
var walk_func = func(filepath string, info fs.DirEntry, err error) error{
if err != nil {
return err
}
if info.IsDir() {
return nil
}
wg.Add(1)
go get_fsha256sum_wrap(filepath)
return nil
}