Ce code sélectionne tous les fichiers xml dans le même dossier, comme l'exécutable appelé et applique le traitement de manière asynchrone à chaque résultat dans la méthode de rappel (dans l'exemple ci-dessous, seul le nom du fichier est imprimé).
Comment éviter d'utiliser la méthode de veille pour empêcher la fermeture de la méthode principale? J'ai du mal à me concentrer sur les canaux (je suppose que c'est ce qu'il faut, pour synchroniser les résultats), donc toute aide est appréciée!
package main
import (
"fmt"
"io/ioutil"
"path"
"path/filepath"
"os"
"runtime"
"time"
)
func eachFile(extension string, callback func(file string)) {
exeDir := filepath.Dir(os.Args[0])
files, _ := ioutil.ReadDir(exeDir)
for _, f := range files {
fileName := f.Name()
if extension == path.Ext(fileName) {
go callback(fileName)
}
}
}
func main() {
maxProcs := runtime.NumCPU()
runtime.GOMAXPROCS(maxProcs)
eachFile(".xml", func(fileName string) {
// Custom logic goes in here
fmt.Println(fileName)
})
// This is what i want to get rid of
time.Sleep(100 * time.Millisecond)
}
go
synchronization
goroutine
Dante
la source
la source
Note that calls with positive delta must happen before the call to Wait, or else Wait may wait for too small a group. Typically this means the calls to Add should execute before the statement creating the goroutine or other event to be waited for. See the WaitGroup example.
wg := new(sync.WaitGroup)
au lieu devar wg sync.WaitGroup
.wg.Add(len(urls))
juste au-dessus de la lignefor _, url := range urls
, je pense que c'est mieux car vous n'utilisez l'ajout qu'une seule fois.go vet
détecte ce cas et avertit avec" func passe le verrouillage par valeur : sync.WaitGroup contient sync.noCopy ".Les WaitGroups sont certainement le moyen canonique de le faire. Par souci d'exhaustivité, cependant, voici la solution qui était couramment utilisée avant l'introduction des WaitGroups. L'idée de base est d'utiliser un canal pour dire «J'ai terminé» et de faire attendre le goroutine principal jusqu'à ce que chaque routine créée ait signalé son achèvement.
la source
doSomething()
renvoie un résultat, vous pouvez le mettre sur le canal, et vous pouvez collecter et traiter les résultats dans la deuxième boucle for (dès qu'ils sont prêts)wg.Add(1)
et ainsi il les suivra . Avec les chaînes, ce serait un peu plus difficile.c
sont différents de la goroutine principale, qui lit à partir dec
. Ainsi, le goroutine principal est toujours disponible pour lire une valeur sur le canal, ce qui se produira lorsque l'un des goroutines est disponible pour écrire une valeur sur le canal. Vous avez raison de dire que si ce code ne généra pas de goroutines mais exécutait tout dans un seul goroutine, il serait dans une impasse.sync.WaitGroup peut vous aider ici.
la source
Bien que
sync.waitGroup
(wg) soit la voie à suivre canonique, cela vous oblige à faire au moins certains de voswg.Add
appels avant vouswg.Wait
pour que tout soit terminé. Cela peut ne pas être possible pour des choses simples comme un robot d'exploration Web, où vous ne connaissez pas à l'avance le nombre d'appels récursifs et il faut un certain temps pour récupérer les données qui génèrent leswg.Add
appels. Après tout, vous devez charger et analyser la première page avant de connaître la taille du premier lot de pages enfants.J'ai écrit une solution utilisant des canaux, en évitant
waitGroup
dans ma solution le Tour of Go - exercice de robot d'exploration Web . Chaque fois qu'une ou plusieurs routines de démarrage sont lancées, vous envoyez le numéro auchildren
canal. Chaque fois qu'une routine go est sur le point de se terminer, vous envoyez un message1
audone
canal. Lorsque la somme des enfants est égale à la somme de done, nous avons terminé.Ma seule préoccupation restante est la taille codée en dur du
results
canal, mais c'est une limitation (actuelle) de Go.Code source complet de la solution
la source
Voici une solution qui utilise WaitGroup.
Tout d'abord, définissez 2 méthodes utilitaires:
Ensuite, remplacez l'invocation de
callback
:Avec un appel à votre fonction utilitaire:
Dernière étape, ajoutez cette ligne à la fin de votre
main
, au lieu de votresleep
. Cela garantira que le thread principal attend que toutes les routines se terminent avant que le programme puisse s'arrêter.la source