Sí, es complicado, pero hay un par de reglas generales que deberían hacer que las cosas se sientan mucho más sencillas.
- prefiera usar argumentos formales para los canales que pasa a las rutinas go en lugar de acceder a los canales en el ámbito global De esta manera, puede obtener más comprobaciones del compilador y también una mejor modularidad.
- evite leer y escribir en el mismo canal en una rutina de marcha en particular (incluida la 'principal'). De lo contrario, el estancamiento es un riesgo mucho mayor.
Aquí hay una versión alternativa de su programa, aplicando estas dos pautas. Este caso demuestra muchos escritores y un lector en un canal:
c := make(chan string)
for i := 1; i <= 5; i++ {
go func(i int, co chan<- string) {
for j := 1; j <= 5; j++ {
co <- fmt.Sprintf("hi from %d.%d", i, j)
}
}(i, c)
}
for i := 1; i <= 25; i++ {
fmt.Println(<-c)
}
http://play.golang.org/p/quQn7xePLw
Crea las cinco rutinas go escribiendo en un solo canal, cada una escribiendo cinco veces. La rutina principal lee los veinticinco mensajes; puede notar que el orden en el que aparecen a menudo no es secuencial (es decir, la concurrencia es evidente).
Este ejemplo demuestra una característica de los canales Go: es posible tener varios escritores compartiendo un canal; Go intercalará los mensajes automáticamente.
Lo mismo se aplica para un escritor y varios lectores en un canal, como se ve en el segundo ejemplo aquí:
c := make(chan int)
var w sync.WaitGroup
w.Add(5)
for i := 1; i <= 5; i++ {
go func(i int, ci <-chan int) {
j := 1
for v := range ci {
time.Sleep(time.Millisecond)
fmt.Printf("%d.%d got %d\n", i, j, v)
j += 1
}
w.Done()
}(i, c)
}
for i := 1; i <= 25; i++ {
c <- i
}
close(c)
w.Wait()
Este segundo ejemplo incluye una espera impuesta a la goroutine principal, que de otro modo saldría rápidamente y provocaría que las otras cinco gorutinas se cancelen antes (gracias a olov por esta corrección) .
En ambos ejemplos, no se necesitó almacenamiento en búfer. En general, es un buen principio considerar el almacenamiento en búfer únicamente como un potenciador del rendimiento. Si su programa no se bloquea sin búfer, tampoco lo hará con búfer (pero lo contrario no siempre es cierto). Entonces, como otra regla general, comience sin almacenar en búfer y luego agréguelo más tarde según sea necesario .
original, hi from 4
...