Go - idiomi / design per determinare quando un numero sconosciuto di goroutine è completo

4

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"?

    
posta Orion Edwards 11.08.2015 - 05:46
fonte

2 risposte

2

Dai documenti per sync.WaitGroup :

A WaitGroup waits for a collection of goroutines to finish. The main goroutine calls Add to set the number of goroutines to wait for. Then each of the goroutines runs and calls Done when finished. At the same time, Wait can be used to block until all goroutines have finished.

    
risposta data 12.04.2016 - 02:37
fonte
1

In passato ho usato qualcosa del genere in Go, per questo esatto caso:

func ProcessFile(fileName string, wg *sync.WaitGroup) {
   defer wg.Done()
   // Do things
}

func ProcessDirectory(dirName string, wg *sync.WaitGroup) {
  defer wg.Done()
  // Do things
  switch {
  case isFile(name): 
    wg.Add(1)
    go processFile(name, wg)
  case isDir(name):
    wg.Add(1)
    go processDirectory(name, wg)
}

Può essere implementato utilizzando una routine di go-go dello stato per contare su e giù, ma una sync.WaitGroup è una soluzione molto più semplice.

    
risposta data 12.04.2016 - 13:12
fonte

Leggi altre domande sui tag