Ho un flusso di lavoro in cui cammino ricorsivamente attraverso un gruppo di directory, quindi ogni file esegue un'azione. Sto usando goroutine per percorrere ogni directory e anche per elaborare ogni file. Il problema che ho è di tenere traccia di quando il lavoro è "finito" dato che ogni directory genera una nuova goroutine e c'è un numero sconosciuto di sottodirectory e file.
La soluzione che sto usando al momento prevede la creazione di un canale secondario che funga da contatore - prima di generare una nuova goroutine facciamo +1 il contatore, e quando la goroutine lo completa, il contatore è -1 e quando il contatore raggiunge 0 sappiamo che abbiamo finito. Fondamentalmente fa questo:
func scanFile(filePath os.FileInfo, result chan string, counter chan int) {
result <- "result of operation"
counter <- -1
}
func scanDir(dir string, result chan string, counter chan int) {
for _, f := range (/*files in dir*/) {
counter <- 1
if f.IsDir() {
go scanFile(f, result, counter)
} else {
go calcCrc32(f, result, counter)
}
}
counter <- -1
}
func main() {
results := make(chan string)
counter := make(chan int, 1) // need a buffered channel due to next line
counter <- 1
go scanDir("some dir", results, counter)
countValue := 0
for {
select {
case result := <- results:
fmt.Printf("got result")
case delta := <- counter:
countValue += delta
if countValue == 0 {
fmt.Println("all done")
return
}
}
}
}
Questo sembra funzionare piuttosto bene, ma sembra un hack assolutamente terribile. Esiste un modello / idioma di design in grado di raggiungere questo obiettivo in modo migliore?
P.S. Penso di poterlo semplificare molto non utilizzando goroutine per la scansione delle directory, e usarle solo a livello di file, ma la domanda continua a essere valida - come si gestiscono le durate di goroutine "ricorsive"?