full - range of channel golang
Cómo esperar a que todos los goroutines terminen sin usar el tiempo. ¿Duerme? (3)
Puede usar sync.WaitGroup . Citando el ejemplo vinculado:
package main
import (
"net/http"
"sync"
)
func main() {
var wg sync.WaitGroup
var urls = []string{
"http://www.golang.org/",
"http://www.google.com/",
"http://www.somestupidname.com/",
}
for _, url := range urls {
// Increment the WaitGroup counter.
wg.Add(1)
// Launch a goroutine to fetch the URL.
go func(url string) {
// Decrement the counter when the goroutine completes.
defer wg.Done()
// Fetch the URL.
http.Get(url)
}(url)
}
// Wait for all HTTP fetches to complete.
wg.Wait()
}
Este código selecciona todos los archivos xml en la misma carpeta, como el ejecutable invocado y aplica de forma asíncrona el procesamiento a cada resultado en el método de devolución de llamada (en el ejemplo siguiente, solo se imprime el nombre del archivo).
¿Cómo evito usar el método de suspensión para evitar que el método principal se cierre? Tengo problemas para entender los canales (supongo que eso es lo que se necesita, para sincronizar los resultados) ¡así que cualquier ayuda es apreciada!
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)
}
WaitGroups es definitivamente la forma canónica de hacer esto. Sin embargo, para completar, esta es la solución que se usaba comúnmente antes de que se introdujeran los WaitGroups. La idea básica es usar un canal para decir "He terminado", y hacer que la rutina principal espere hasta que cada rutina generada haya informado de su finalización.
func main() {
c := make(chan struct{}) // We don''t need any data to be passed, so use an empty struct
for i := 0; i < 100; i++ {
go func() {
doSomething()
c <- struct{}{} // signal that the routine has completed
}()
}
// Since we spawned 100 routines, receive 100 messages.
for i := 0; i < 100; i++ {
<- c
}
}
sync.WaitGroup puede ayudarlo aquí.
package main
import (
"fmt"
"sync"
"time"
)
func wait(seconds int, wg * sync.WaitGroup) {
defer wg.Done()
time.Sleep(time.Duration(seconds) * time.Second)
fmt.Println("Slept ", seconds, " seconds ..")
}
func main() {
var wg sync.WaitGroup
for i := 0; i <= 5; i++ {
wg.Add(1)
go wait(i, &wg)
}
wg.Wait()
}