Dieser Code wählt alle XML-Dateien im selben Ordner aus, da die aufgerufene ausführbare Datei die Verarbeitung asynchron auf jedes Ergebnis der Rückrufmethode anwendet (im folgenden Beispiel wird nur der Name der Datei ausgedruckt).
Wie vermeide ich die Verwendung der Schlafmethode, um zu verhindern, dass die Hauptmethode beendet wird? Ich habe Probleme, meinen Kopf um Kanäle zu wickeln (ich nehme an, das ist nötig, um die Ergebnisse zu synchronisieren), daher ist jede Hilfe willkommen!
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
quelle
quelle
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)
anstelle vonvar wg sync.WaitGroup
.wg.Add(len(urls))
direkt über der Zeile zu schreiben.for _, url := range urls
Ich glaube, es ist besser, wenn Sie das Hinzufügen nur einmal verwenden.go vet
erkennt es diesen Fall jedoch und warnt mit" func übergibt die Sperre nach Wert : sync.WaitGroup enthält sync.noCopy ".WaitGroups sind definitiv der kanonische Weg, dies zu tun. Der Vollständigkeit halber ist hier die Lösung, die üblicherweise vor der Einführung von WaitGroups verwendet wurde. Die Grundidee besteht darin, einen Kanal zu verwenden, um "Ich bin fertig" zu sagen, und die Hauptgoroutine warten zu lassen, bis jede gespawnte Routine ihren Abschluss gemeldet hat.
quelle
doSomething()
ein Ergebnis zurückgegeben wird, können Sie es auf den Kanal setzen und die Ergebnisse in der zweiten for-Schleife sammeln und verarbeiten (sobald sie fertig sind)wg.Add(1)
und somit den Überblick behalten. Mit Kanälen wäre es etwas schwieriger.c
sich von der Hauptgoroutine unterscheiden, aus der gelesen wirdc
. Somit ist die Hauptgoroutine immer verfügbar, um einen Wert aus dem Kanal zu lesen. Dies geschieht, wenn eine der Goroutinen verfügbar ist, um einen Wert in den Kanal zu schreiben. Sie haben Recht, wenn dieser Code keine Goroutinen hervorbringt, sondern alles in einer einzigen Goroutine ausführt, würde er zum Stillstand kommen.sync.WaitGroup kann Ihnen hier helfen.
quelle
Obwohl
sync.waitGroup
(wg) der kanonische Weg nach vorne ist, müssen Sie zumindest einige Ihrerwg.Add
Anrufe vor Ihnen tätigen,wg.Wait
damit alle fertig sind. Dies ist möglicherweise für einfache Dinge wie einen Webcrawler nicht möglich, bei denen Sie die Anzahl der rekursiven Aufrufe im Voraus nicht kennen und es eine Weile dauert, bis die Daten abgerufen sind, die diewg.Add
Aufrufe steuern. Schließlich müssen Sie die erste Seite laden und analysieren, bevor Sie die Größe des ersten Stapels untergeordneter Seiten kennen.Ich habe eine Lösung über Kanäle geschrieben und
waitGroup
in meiner Lösung die Tour of Go - Web-Crawler- Übung vermieden . Jedes Mal, wenn eine oder mehrere Go-Routinen gestartet werden, senden Sie die Nummer an denchildren
Kanal. Jedes Mal, wenn eine Go-Routine abgeschlossen ist, senden Sie eine1
an dendone
Kanal. Wenn die Summe der Kinder gleich der Summe der erledigten Kinder ist, sind wir fertig.Meine einzige verbleibende Sorge ist die fest codierte Größe des
results
Kanals, aber das ist eine (aktuelle) Go-Einschränkung.Vollständiger Quellcode für die Lösung
quelle
Hier ist eine Lösung, die WaitGroup verwendet.
Definieren Sie zunächst zwei Dienstprogrammmethoden:
Ersetzen Sie dann den Aufruf von
callback
:Mit einem Aufruf Ihrer Utility-Funktion:
Im letzten Schritt fügen Sie diese Zeile am Ende Ihres
main
statt Ihres hinzusleep
. Dadurch wird sichergestellt, dass der Hauptthread auf den Abschluss aller Routinen wartet, bevor das Programm gestoppt werden kann.quelle