Skip to content

Instantly share code, notes, and snippets.

@MrSaints
Created May 25, 2017 16:15
Show Gist options
  • Save MrSaints/3e68e8899eb9d1d0672f46a498513818 to your computer and use it in GitHub Desktop.
Save MrSaints/3e68e8899eb9d1d0672f46a498513818 to your computer and use it in GitHub Desktop.
Coffee shop concurrency. Examining concurrency in the real world by scaling a coffee shop's efficiency.
package main
import (
"fmt"
"github.com/icrowley/fake"
"math/rand"
"time"
)
const (
averageTimeToNextCustomer = 3
averageWaitingTime = 3
)
var (
acceptedOrders int = 0
missedOrders int = 0
)
type Brewable interface {
Brew()
String() string
}
type Americano struct{}
type Cappuccino struct{}
type Latte struct{}
type Customer struct {
Name string
}
type Order struct {
Number int
Type Brewable
Customer *Customer
}
func (c *Americano) Brew() {
fmt.Println("Brewing an", c.String())
time.Sleep(time.Second * 5)
}
func (c *Americano) String() string {
return "Americano"
}
func (c *Cappuccino) Brew() {
fmt.Println("Brewing a", c.String())
time.Sleep(time.Second * time.Duration(rand.Intn(7)+7))
}
func (c *Cappuccino) String() string {
return "Cappuccino"
}
func (c *Latte) Brew() {
fmt.Println("Brewing a", c.String())
time.Sleep(time.Second * time.Duration(rand.Intn(10)+10))
}
func (c Latte) String() string {
return "Latte"
}
func init() {
rand.Seed(time.Now().UTC().UnixNano())
}
func generateOrders(orderQueue chan<- *Order) {
// Menu
coffees := []Brewable{&Americano{}, &Cappuccino{}, &Latte{}}
customerNumber := 0
for {
customerName := fake.FirstName()
fmt.Printf("[%d] %s entered the shop.\n", customerNumber, customerName)
order := &Order{
Number: customerNumber,
Type: coffees[rand.Intn(len(coffees))],
Customer: &Customer{Name: customerName},
}
customerNumber += 1
select {
case orderQueue <- order:
acceptedOrders += 1
fmt.Printf("[%d] %s ordered %s.\n", order.Number, customerName, order.Type.String())
case <-time.After(time.Second * time.Duration(averageWaitingTime)):
missedOrders += 1
fmt.Printf("[%d] %s got impatient waiting to order %s, and left.\n", order.Number, customerName, order.Type.String())
}
time.Sleep(time.Second * time.Duration(rand.Intn(averageTimeToNextCustomer)))
}
}
func handleOrders(orderQueue <-chan *Order, baristaName string) {
for order := range orderQueue {
order.Type.Brew()
fmt.Printf("[%d] %s brewed %s for %s\n", order.Number, baristaName, order.Type.String(), order.Customer.Name)
}
}
func main() {
defer func() {
fmt.Println("Accepted orders:", acceptedOrders)
fmt.Println("Missed orders:", missedOrders)
}()
// Order queue
orderQueue := make(chan *Order, 5)
// Cashiers
go generateOrders(orderQueue)
// Baristas
go handleOrders(orderQueue, "Ian")
go handleOrders(orderQueue, "Harry")
go handleOrders(orderQueue, "Roey")
// Close the coffee shop
time.Sleep(30 * time.Second)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment