Skip to content

Instantly share code, notes, and snippets.

@Dainerx
Last active November 30, 2020 17:17
Show Gist options
  • Save Dainerx/0c142a110161fe229a5107f746a62c3f to your computer and use it in GitHub Desktop.
Save Dainerx/0c142a110161fe229a5107f746a62c3f to your computer and use it in GitHub Desktop.
Simulating a chapatti store
package main
import (
"fmt"
"log"
"math/rand"
"time"
)
type ChappatiStore struct {
Verbose bool // True for logs from go routines
ChappatiToMake int // number of chappati to make
Bakers int // number of cooks doing baking
BakeMeanTime time.Duration // mean time to prepare dough for one chappati
BakeStdDev time.Duration // standard deviation of preparing dough for one chappati
BakeBufferSize int // buffer slots between baking and making
Makers int // number of chappati makers
MakeMeanTime time.Duration // mean time to make one chappati
MakeStdDev time.Duration // standard deviation for making one chappati with baked dough
MakeBufferSize int // buffer slots between making and packaging
PackageMeanTime time.Duration // mean time to package one sandwitch
PackageStdDev time.Duration // standard deviation for packaging one made chappati
}
type chappati int
// bake a chappati and send it to the baked channel.
func (ch *ChappatiStore) baker(baked chan<- chappati, toBake <-chan chappati) {
for c := range toBake {
if ch.Verbose {
log.Println("baking", c)
}
work(ch.BakeMeanTime, ch.BakeStdDev)
baked <- c
}
}
// retrive from the baked channel a dough and make a chappati with it.
func (ch *ChappatiStore) maker(made chan<- chappati, baked <-chan chappati) {
for c := range baked {
if ch.Verbose {
log.Println("making", c)
}
work(ch.MakeMeanTime, ch.MakeStdDev)
made <- c
}
}
// package a prepared a made chappati.
func (ch *ChappatiStore) packager(made <-chan chappati) {
for i := 0; i < ch.ChappatiToMake; i++ {
c := <-made
if ch.Verbose {
log.Println("packaging", c)
}
work(ch.PackageMeanTime, ch.PackageStdDev)
if ch.Verbose {
log.Println("sold", c)
}
}
}
// work blocks the calling goroutine for a period of time
// that is normally distributed around mean with a standard deviation of stddev.
func work(mean, stddev time.Duration) time.Duration {
delay := mean + time.Duration(rand.NormFloat64()*float64(stddev))
time.Sleep(delay)
return delay
}
func (ch *ChappatiStore) Configuration() string {
var config string
config += fmt.Sprintf("Baking{Bakers:%d,BakeStdDev:%v,BakeMeanTime:%v,BakeBufferSize:%d}\n",
ch.Bakers, ch.BakeStdDev, ch.BakeMeanTime, ch.BakeBufferSize)
config += fmt.Sprintf("Making{Makers:%d,MakeStdDev:%v,MakeMeanTime:%v,MakeBufferSize:%d}\n",
ch.Makers, ch.MakeStdDev, ch.MakeMeanTime, ch.MakeBufferSize)
config += fmt.Sprintf("Packaging{PackageMeanTime:%v,PackageStdDev:%v}\n",
ch.PackageMeanTime, ch.PackageStdDev)
return config
}
// Run
func (ch *ChappatiStore) Run() time.Duration {
toBake := make(chan chappati, ch.ChappatiToMake)
baked := make(chan chappati, ch.BakeBufferSize)
made := make(chan chappati, ch.MakeBufferSize)
for i := 0; i < ch.ChappatiToMake; i++ {
toBake <- chappati(i)
}
start := time.Now()
// for every baker launch the bake method on different routine
for i := 0; i < ch.Bakers; i++ {
go ch.baker(baked, toBake)
}
for i := 0; i < ch.Makers; i++ {
go ch.maker(made, baked)
}
ch.packager(made)
return time.Since(start)
}
func main() {
ch := ChappatiStore{
Verbose: true, // display goroutines progress
ChappatiToMake: 50,
Bakers: 10,
BakeStdDev: 10 * time.Millisecond,
BakeMeanTime: 500 * time.Millisecond,
BakeBufferSize: 1,
Makers: 5,
MakeStdDev: 10 * time.Millisecond,
MakeMeanTime: 50 * time.Millisecond,
MakeBufferSize: 1,
PackageMeanTime: 100 * time.Millisecond,
}
fmt.Printf("We closed, took %v to prepare %d chappatis.\n", ch.Run(), ch.ChappatiToMake)
fmt.Print(ch.Configuration())
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment