1 La variable f est partagée par toutes les valeurs de fonctions anonymes et sera mise à jour par des itérations de boucle successives.
2 . Au moment où la nouvelle goroutine commence à exécuter la fonction littérale, la boucle for peut avoir mis à jour f et commencé une autre itération ou (plus probablement) a terminé la boucle entière,
func makeThumbnails6(filenames <-chan string) int64 {
sizes := make(chan int64)
var wg sync.WaitGroup // number of working goroutines
for f := range filenames {
wg.Add(1)
// worker
go func(f string) {
defer wg.Done()
thumb, err := thumbnail.ImageFile(f)
if err != nil {
log.Println(err)
return
}
info, _ := os.Stat(thumb) // OK to ignore error
sizes <- info.Size()
}(f)
}
// closer
go func() {
wg.Wait()
close(sizes)
}()
var total int64
for size := range sizes {
total += size
}
return total
}
Add doit être appelé avant que la goroutine de travail ne démarre, il n'y a aucun moyen d'être sûr que Add est appelé avant que la goroutine "plus proche" appelle Wait.
Fonctionnement en deux étapes : fermeture après attente,
Si l'opération en deux étapes est placée dans la goroutine principale, avant la boucle, alors elle ne se terminera jamais,
- car il n'y a pas de boucle de plage pour accepter size: = tailles de plage, done ne se terminera jamais.
如果在循环之后,那么又变成了不可达的部分,因为没有任何东西去关闭这个channel,这个循环就永远都不会终止。
(当channel没有 数据 总会阻塞这个channel)