publish more advanced channel examples

This commit is contained in:
Mark McGranaghan 2012-10-18 07:16:55 -07:00
parent 86867c9cff
commit b044506449
9 changed files with 84 additions and 70 deletions

View File

@ -27,15 +27,15 @@ Recursion
Goroutines Goroutines
Channels Channels
Channel Buffering Channel Buffering
# Channel Directions Channel Synchronization
# Synchronization Channel Directions
Select Select
Timeouts Timeouts
Non-Blocking Channel Operations
# Closing Channels
# Scatter Gather # Scatter Gather
# Rate Limiting # Rate Limiting
# Worker Pools # Worker Pools
# Non-Blocking Channel Operations
# Closing Channels
Timers Timers
Tickers Tickers
# State Goroutine # State Goroutine

View File

@ -1,35 +1,30 @@
// When using channels as function parameters, you can
// specify if a channel is meant to only send or receive
// values. This specificity further increases the
// type-safety of the program.
package main package main
import "fmt" import "fmt"
func pinger(pings chan<- string) { // This `ping` function only accepts a channel for sending
for i := 0; i <= 10; i++ { // values. It would be a compile-time error to try to
pings <- "ping" // receive on this channel.
} func ping(pings chan<- string, msg string) {
pings <- msg
} }
func ponger(pings <-chan string, pongs chan<- string) { // The `pong` function accepts one channel for receives
for { // (`pings`) and a second for sends (`pongs`)
<-pings func pong(pings <-chan string, pongs chan<- string) {
pongs <- "pong" msg := <-pings
} pongs <- msg
}
func printer(pongs <-chan string) {
for {
msg := <-pongs
fmt.Println(msg)
}
} }
func main() { func main() {
var pings chan string = make(chan string) pings := make(chan string, 1)
var pongs chan string = make(chan string) pongs := make(chan string, 1)
ping(pings, "passed message")
go pinger(pings) pong(pings, pongs)
go ponger(pings, pongs) fmt.Println(<-pongs)
go printer(pongs)
var input string
fmt.Scanln(&input)
} }

View File

@ -0,0 +1,2 @@
$ go run channel-directions.go
passed message

View File

@ -0,0 +1,32 @@
// We can use channels to synchronize execution
// across goroutines. Here's an example of using a
// blocking receive to wait for a goroutine to finish.
package main
import "fmt"
import "time"
// This is the function we'll run in a goroutine. The
// `done` channel will be used to notify another
// goroutine that this function's work is done.
func worker(done chan bool) {
fmt.Print("working...")
time.Sleep(time.Second)
fmt.Println(" done")
// Send a value to notify that we're done.
done <- true
}
func main() {
// Start a worker goroutine, giving it the channel to
// notify on.
done := make(chan bool, 1)
go worker(done)
// Block until we receive a notification from the
// worker on the channel.
<-done
}

View File

@ -0,0 +1,6 @@
$ go run channel-synchronization.go
working...done
# If you removed the `<- done` line from this program, the
# program would exit before the `worker` even
# started.

View File

@ -1,3 +1,8 @@
// Basic sends and receives on channels are blocking.
// However, we can use `select` with a `default` clause to
// implement _non-blocking_ sends, receives, and even
// non-blocking multi-way `select`s.
package main package main
import "fmt" import "fmt"
@ -6,24 +11,30 @@ func main() {
messages := make(chan string) messages := make(chan string)
signals := make(chan bool) signals := make(chan bool)
// Non-blocking receive. // Here's a non-blocking receive. If a value is
// available on `messages` then `select` will take
// the `<-messages` `case` with that value. If not
// it will immediately take the `default` case.
select { select {
case msg := <-messages: case msg := <-messages:
fmt.Println("received message", msg) fmt.Println("received message", msg)
default: default:
fmt.Println("no messages received") fmt.Println("no message received")
} }
// Non-blocking send. // A non-blocking send works similarly.
msg := "hi" msg := "hi"
select { select {
case messages <- msg: case messages <- msg:
fmt.Println("sent message", msg) fmt.Println("sent message", msg)
default: default:
fmt.Println("no messages sent") fmt.Println("no message sent")
} }
// Non-blocking multi-way select. // We can use multiple `case`s above the `default`
// clause to implement a multi-way non-blocking
// select. Here we attempt non-blocking receives
// on both `messages` and `signals`.
select { select {
case msg := <-messages: case msg := <-messages:
fmt.Println("received message", msg) fmt.Println("received message", msg)

View File

@ -0,0 +1,4 @@
$ go run non-blocking-channel-operations.go
no message received
no message sent
no activity

View File

@ -1,30 +0,0 @@
// We can use channels to synchronize execution
// accross goroutines. Here's an example of waiting
// for another goroutine to finish.
package main
import "fmt"
import "time"
// The `done` channel will be used for
// synchronization.
func worker(done chan<- bool) {
fmt.Print("Working...")
time.Sleep(time.Second)
fmt.Println(" done")
// Send a value to notify that the work is done.
done <- true
}
func main() {
// Start a worker goroutine, give it the channel to
// notify on.
done := make(chan bool, 1)
go worker(done)
// Block until we can receive a value from the worker
// over the channel.
<-done
}

View File

@ -1,6 +0,0 @@
$ go run synchronization.go
Working... done
# If you commented out the `<- done` line, the
# program would exit before the `worker` even
# started.