Skip to content

Instantly share code, notes, and snippets.

@timblair
Created November 6, 2015 08:51
Show Gist options
  • Save timblair/f4cc410769e7a868dfed to your computer and use it in GitHub Desktop.
Save timblair/f4cc410769e7a868dfed to your computer and use it in GitHub Desktop.
Quick stabs at these Go concurrency exercises: http://bit.ly/go-concurrency-exercises
package main
import (
"fmt"
"math/rand"
"sync"
"time"
)
type person string
func (p *person) doActivity(a string, min int, max int, wg *sync.WaitGroup) {
wg.Add(1)
fmt.Println(*p, "started", a)
go func() {
defer wg.Done()
t := time.Second * time.Duration(min+rand.Intn(max-min))
time.Sleep(t)
fmt.Println(*p, "spent", t.Seconds(), "seconds", a)
}()
}
func (p *person) GetReady(wg *sync.WaitGroup) {
p.doActivity("getting ready", 60, 90, wg)
}
func (p *person) PutOnShoes(wg *sync.WaitGroup) {
p.doActivity("putting on shoes", 35, 45, wg)
}
type alarm struct{}
func (a *alarm) Arm() *time.Timer {
return time.NewTimer(60 * time.Second)
}
func init() {
rand.Seed(time.Now().UTC().UnixNano())
}
func main() {
fmt.Println("Let's got for a walk!")
var wg sync.WaitGroup
bob, alice := person("Bob"), person("Alice")
// 1. Bob and Alice get ready
bob.GetReady(&wg)
alice.GetReady(&wg)
wg.Wait()
// 2. Once both are ready, arm alarm
fmt.Println("Arming alarm")
countdown := new(alarm).Arm()
fmt.Println("Alarm is counting down")
// 3. Bob and Alice put on their shoes
bob.PutOnShoes(&wg)
alice.PutOnShoes(&wg)
wg.Wait()
// 4. Leave the house together and close the door
fmt.Println("Exiting and locking the door")
// 5. Alarm is armed
<-countdown.C
fmt.Println("Alarm is armed")
}
package main
import (
"fmt"
"math/rand"
"sync"
"time"
)
type diner string
func (d *diner) Eat(buffet <-chan string) {
for {
select {
case m, ok := <-buffet:
// If the channel is closed, the buffet is empty
if !ok {
return
}
fmt.Println(*d, "is enjoying some", m)
t := time.Second * time.Duration(1+rand.Intn(6))
time.Sleep(t)
}
}
}
func init() {
rand.Seed(time.Now().UTC().UnixNano())
}
func main() {
fmt.Println("Bon appétite!")
diners := []diner{"Alice", "Bob", "Charlie", "Dave"}
dishes := []string{
"chorizo",
"chopitos",
"pimientos de padrón",
"croquetas",
"patatas bravas",
}
buffet := make(chan string)
var wg sync.WaitGroup
// Sit all the diners at the table, ready to eat
for _, d := range diners {
wg.Add(1)
go func(d diner) {
defer wg.Done()
d.Eat(buffet)
}(d)
}
// Cook up 5-10 morsels of each dish
morsels := []string{}
for _, dish := range dishes {
for i := 0; i < 5+rand.Intn(5); i++ {
morsels = append(morsels, dish)
}
}
// Add all the morsels to the buffet in a random order
go func() {
order := rand.Perm(len(morsels))
for _, i := range order {
buffet <- morsels[i]
}
// Close the buffest to signify everything's been eaten
close(buffet)
}()
// Wait for all diners to finish eating
wg.Wait()
fmt.Println("That was delicious!")
}
package main
import (
"fmt"
"math/rand"
"time"
)
type computer struct{}
func (c *computer) Use(t int) {
fmt.Println("Tourist", t, "is online")
d := time.Second * time.Duration(1+rand.Intn(6))
time.Sleep(d)
fmt.Println("Tourist", t, "is done, having spent", d, "online")
}
func init() {
rand.Seed(time.Now().UTC().UnixNano())
}
func main() {
terminals := make(chan *computer, 5)
for i := 0; i < cap(terminals); i++ {
terminals <- new(computer)
}
for _, t := range rand.Perm(25) {
select {
case c := <-terminals:
go func(t int) {
defer func() {
// Add the now-free computer back to the pool
terminals <- c
}()
c.Use(t)
}(t)
}
}
fmt.Println("The place is empty, let's close up and go to the beach!")
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment