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
Channels
Channel Buffering
# Channel Directions
# Synchronization
Channel Synchronization
Channel Directions
Select
Timeouts
Non-Blocking Channel Operations
# Closing Channels
# Scatter Gather
# Rate Limiting
# Worker Pools
# Non-Blocking Channel Operations
# Closing Channels
Timers
Tickers
# 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
import "fmt"
func pinger(pings chan<- string) {
for i := 0; i <= 10; i++ {
pings <- "ping"
}
// This `ping` function only accepts a channel for sending
// values. It would be a compile-time error to try to
// receive on this channel.
func ping(pings chan<- string, msg string) {
pings <- msg
}
func ponger(pings <-chan string, pongs chan<- string) {
for {
<-pings
pongs <- "pong"
}
}
func printer(pongs <-chan string) {
for {
msg := <-pongs
fmt.Println(msg)
}
// The `pong` function accepts one channel for receives
// (`pings`) and a second for sends (`pongs`)
func pong(pings <-chan string, pongs chan<- string) {
msg := <-pings
pongs <- msg
}
func main() {
var pings chan string = make(chan string)
var pongs chan string = make(chan string)
go pinger(pings)
go ponger(pings, pongs)
go printer(pongs)
var input string
fmt.Scanln(&input)
pings := make(chan string, 1)
pongs := make(chan string, 1)
ping(pings, "passed message")
pong(pings, pongs)
fmt.Println(<-pongs)
}

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
import "fmt"
@ -6,24 +11,30 @@ func main() {
messages := make(chan string)
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 {
case msg := <-messages:
fmt.Println("received message", msg)
default:
fmt.Println("no messages received")
fmt.Println("no message received")
}
// Non-blocking send.
// A non-blocking send works similarly.
msg := "hi"
select {
case messages <- msg:
fmt.Println("sent message", msg)
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 {
case msg := <-messages:
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.