diff --git a/examples.txt b/examples.txt index bb041a6..c2446fb 100644 --- a/examples.txt +++ b/examples.txt @@ -31,7 +31,7 @@ Channels # Channel Buffering # Channel Directions # Synchronization -# Select +Select # Timeouts # Scatter Gather # Rate Limiting diff --git a/examples/goroutines/goroutines.go b/examples/goroutines/goroutines.go index f3539e8..e7e47c4 100644 --- a/examples/goroutines/goroutines.go +++ b/examples/goroutines/goroutines.go @@ -13,12 +13,13 @@ func f(from string) { func main() { // Suppose we have a function call `f(s)`. Here's how - // we'd call that in the usual way, running it inline. + // we'd call that in the usual way, running it + // synchronously. f("direct") // To invoke this function in a goroutine, use - // `go f(s)`. This will start a new, concurrently - // executing goroutine. + // `go f(s)`. This new goroutine will execute + // concurrently with the current one. go f("goroutine") // You can also start a goroutine for an anonymous @@ -27,7 +28,7 @@ func main() { fmt.Println("going") }() - // Our two goroutines are running asynchrously in + // Our two goroutines are running asynchronously in // separate goroutines now, so execution falls through // to here. This `Scanln` code requires we press a key // before the program exits. diff --git a/examples/goroutines/goroutines.sh b/examples/goroutines/goroutines.sh index 4869383..9f5672d 100644 --- a/examples/goroutines/goroutines.sh +++ b/examples/goroutines/goroutines.sh @@ -1,5 +1,5 @@ # When we run this program, we see the output of the -# direct call first, then the interleaved output of the +# blocking call first, then the interleaved output of the # two gouroutines. This interleaving reflects the # goroutines being run concurrently by the Go runtime. $ go run goroutines.go diff --git a/examples/select/select.go b/examples/select/select.go index 87c7c4e..5c0d961 100644 --- a/examples/select/select.go +++ b/examples/select/select.go @@ -1,32 +1,52 @@ +// Go's _select_ lets you wait on multiple channel +// operations. Combining goroutines and channels with +// select is powerful feature of Go. + package main import "time" import "fmt" func main() { + + // For our example we'll select accross two channels. c1 := make(chan string) c2 := make(chan string) + + // This third channel will indicate when we're done + // and can exit the program. d := make(chan bool, 1) + // The first two channels will receive a value after + // some amount of time, to simulate e.g. blocking RPC + // operations executing in concurrent goroutines. go func() { time.Sleep(time.Second * 1) - c1 <- "from 1" + c1 <- "one" }() go func() { time.Sleep(time.Second * 2) - c2 <- "from 2" + c2 <- "two" }() + // We'll use `select` to await both of these values + // simultaneously, printing each one as it arrives. + // Once we've received both, we'll send a value to the + // `d` channel indicating that we're ready to proceed. go func() { for i := 0; i < 2; i++ { select { case msg1 := <-c1: - fmt.Println(msg1) + fmt.Println("received", msg1) case msg2 := <-c2: - fmt.Println(msg2) + fmt.Println("received", msg2) } } d <- true }() + + // Since all other code is running in concurrent + // goroutines, we'll executing a blocking receive + // here to await completion of our example. <-d } diff --git a/examples/select/select.sh b/examples/select/select.sh new file mode 100644 index 0000000..2895b86 --- /dev/null +++ b/examples/select/select.sh @@ -0,0 +1,10 @@ +# We receive the values `"one"` and then `"two"` as +# expected. +$ time go run select.go +received one +received two + +# Note that the total execution time is only ~2 seconds +# since both the 1 and 2 second `Sleeps` execute +# concurrently. +real 0m2.245s