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.