Operazioni non Bloccanti
Quando si opera con i channels bisogna sempre porre molta attenzione alle situazioni di blocco.
Esempio
(290non-blockng-channel-operations.go):
package main
import "fmt"
//import "time"
func main() {
// I channel non bufferizzati sono bloccanti
messages := make(chan string)
signals := make(chan bool)
// Attenzione il seguente codice produce
// un deadlock
// messages <- "hello"
// Il seguente codice invece non blocca
// perchè in un thread differente
// go func() {
// messages <- "hello"
// }()
go func() {
messages <- "hello"
}()
// ma se è ricevuto o no è aleatorio
// a meno di attendere che la goroutine operi
// scommentando il codice seguente
// (scommentare anche lo import necessari
// time.Sleep(time.Second)
// Implementazione di un receive non bloccante
select {
case msg := <-messages:
fmt.Println("received message", msg)
// Se non c'è subito un messaggio scatta il default
default:
fmt.Println("no message received")
}
// Un send non bloccante
msg := "hi"
select {
case messages <- msg:
fmt.Println("sent message", msg)
default:
fmt.Println("no message sent")
}
// Select multiplo non bloccante
select {
case msg := <-messages:
fmt.Println("received message", msg)
case sig := <-signals:
fmt.Println("received signal", sig)
default:
fmt.Println("no activity")
}
}
Come si nota una select
, come uno switch
, può avere un case di default
, che è sempre soddisfatto a meno che non sia stato soddisfatto uno dei case precedenti.
Nel nostro esempio quasi sicuramente interviene sempre la situazione di default perchè la goroutine che emette il messaggio probabilmente non ha avuto ancora tempo di operare, Quando il main esegue il select.
In una situazione vera o vi sarebbe qualche tipo di ritardo prima del select, oppure vi sarebbe un loop per iterare sul select più volte.