publish more advanced channel examples
This commit is contained in:
parent
86867c9cff
commit
b044506449
@ -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
|
||||||
|
@ -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)
|
|
||||||
}
|
}
|
||||||
|
2
examples/channel-directions/channel-directions.sh
Normal file
2
examples/channel-directions/channel-directions.sh
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
$ go run channel-directions.go
|
||||||
|
passed message
|
32
examples/channel-synchronization/channel-synchronization.go
Normal file
32
examples/channel-synchronization/channel-synchronization.go
Normal 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
|
||||||
|
}
|
@ -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.
|
@ -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)
|
||||||
|
@ -0,0 +1,4 @@
|
|||||||
|
$ go run non-blocking-channel-operations.go
|
||||||
|
no message received
|
||||||
|
no message sent
|
||||||
|
no activity
|
@ -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
|
|
||||||
}
|
|
@ -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.
|
|
Loading…
x
Reference in New Issue
Block a user