Недавно я посмотрел на ходу и зацепился, это выглядит так интересно! После завершения учебного пособия мне захотелось что-то создать самостоятельно: я хочу перечислить все свои песни из своей музыкальной библиотеки. Я думаю, что я могу получить прибыль от параллелизма с вами. В то время как на рутине идет по дереву каталогов, он подталкивает музыкальные файлы (путь к этим файлам) в канал, который затем подбирается другой подпрограммой, которая читает теги ID3, поэтому мне не нужно ждать, пока не будет найден все файлы ,Ошибка тупика в golang
Это мой простой и наивный подход:
package main
import (
"fmt"
"os"
"path/filepath"
"strings"
"sync"
)
const searchPath = "/Users/luma/Music/test" // 5GB of music.
func main() {
files := make(chan string)
var wg sync.WaitGroup
wg.Add(2)
go printHashes(files, &wg)
go searchFiles(searchPath, files, &wg)
wg.Wait()
}
func searchFiles(searchPath string, files chan<- string, wg *sync.WaitGroup) {
visit := func(path string, f os.FileInfo, err error) error {
if !f.IsDir() && strings.Contains(".mp4.mp3.flac", filepath.Ext(f.Name())) {
files <- path
}
return err
}
if err := filepath.Walk(searchPath, visit); err != nil {
fmt.Println(err)
}
wg.Done()
}
func printHashes(files <-chan string, wg *sync.WaitGroup) {
for range files {
fmt.Println(<-files)
}
wg.Done()
}
Эта программа не читает теги, пока. Вместо этого он просто печатает путь к файлу. Это работает, он перечисляет все музыкальные файлы очень быстро! Но я вижу эту ошибку после завершения программы:
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [semacquire]:
sync.runtime_Semacquire(0xc42007205c)
/usr/local/Cellar/go/1.7.4_2/libexec/src/runtime/sema.go:47 +0x30
sync.(*WaitGroup).Wait(0xc420072050)
/usr/local/Cellar/go/1.7.4_2/libexec/src/sync/waitgroup.go:131 +0x97
main.main()
/Users/luma/Code/Go/src/github.com/LuMa/test/main.go:22 +0xfa
goroutine 17 [chan receive]:
main.printHashes(0xc42008e000, 0xc420072050)
/Users/luma/Code/Go/src/github.com/LuMa/test/main.go:42 +0xb4
created by main.main
/Users/luma/Code/Go/src/github.com/LuMa/test/main.go:19 +0xab
exit status 2
Что вызывает тупик?
Всегда откладывайте WaitGroup.Done(). У вас есть обратный путь в вашем первом goroutine, который не вызывает Done. – JimB
@ JimB, который меня тоже доставил. Но обратите внимание, что это не путь возврата - это встроенный func, объявленный и переданный в другую функцию, которая имеет только один путь выполнения. Но да, типичные практики требуют вызова 'defer wg.Done()' – eduncan911
@ eduncan911: oops, thanks. Просто сканировался на ранние возвращения и не читал достаточно внимательно. – JimB