Created
May 25, 2017 16:15
-
-
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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