Программа блокируется на for v := range c
, потому что диапазон на канале продолжается до тех пор, пока канал не будет закрыт. Исправьте, получив ожидаемое количество значений. WaitGroup не требуется с этим изменением.
result := true
stats := make(map[string]bool)
fmt.Println(`total sites: `, len(links))
c := make(chan urlState, len(links))
for _, link := range links {
stats[link] = false
fmt.Println(`requesting...`, link)
go checkLink(link, c)
fmt.Println(`goroutines: `, runtime.NumGoroutine())
}
for i := 0; i < len(links); i++ {
v := <-c
fmt.Println(`recv from channel, assigning result for `, v.url)
stats[v.url] = v.state
fmt.Println(`goroutines: `, runtime.NumGoroutine())
}
fmt.Println(`work finished!`)
for key, value := range stats {
fmt.Println(key, `---`, value)
if value == false {
result = false
}
}
Запустите его на игровой площадке
Другой способ решить проблему - закрыть c
после checkLink
Горутины завершены. Используйте WaitGroup, чтобы координировать это.
func checkLink(link string, c chan<- urlState, wg *sync.WaitGroup) {
defer wg.Done()
... remainder of function is same as before
}
func Check(links []string) bool {
result := true
stats := make(map[string]bool)
var wg sync.WaitGroup
fmt.Println(`total sites: `, len(links))
wg.Add(len(links)) // add workgroups of exactly same amount as links array length
c := make(chan urlState, len(links))
for _, link := range links {
stats[link] = false
fmt.Println(`requesting...`, link)
go checkLink(link, c, &wg)
fmt.Println(`goroutines: `, runtime.NumGoroutine())
}
// Close c when checkLink goroutines complete.
go func() {
wg.Wait()
close(c)
}()
for v := range c {
fmt.Println(`recv from channel, assigning result for `, v.url)
stats[v.url] = v.state
wg.Done()
fmt.Println(`goroutines: `, runtime.NumGoroutine())
}
fmt.Println(`work finished!`)
for key, value := range stats {
fmt.Println(key, `---`, value)
if value == false {
result = false
}
}
return result
}
Запустите его на детской площадке