Permalink
Cannot retrieve contributors at this time
Fetching contributors…
| // Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan. | |
| // License: https://creativecommons.org/licenses/by-nc-sa/4.0/ | |
| // See page 234. | |
| // Package cake provides a simulation of | |
| // a concurrent cake shop with numerous parameters. | |
| // | |
| // Use this command to run the benchmarks: | |
| // $ go test -bench=. gopl.io/ch8/cake | |
| package cake | |
| import ( | |
| "fmt" | |
| "math/rand" | |
| "time" | |
| ) | |
| type Shop struct { | |
| Verbose bool | |
| Cakes int // number of cakes to bake | |
| BakeTime time.Duration // time to bake one cake | |
| BakeStdDev time.Duration // standard deviation of baking time | |
| BakeBuf int // buffer slots between baking and icing | |
| NumIcers int // number of cooks doing icing | |
| IceTime time.Duration // time to ice one cake | |
| IceStdDev time.Duration // standard deviation of icing time | |
| IceBuf int // buffer slots between icing and inscribing | |
| InscribeTime time.Duration // time to inscribe one cake | |
| InscribeStdDev time.Duration // standard deviation of inscribing time | |
| } | |
| type cake int | |
| func (s *Shop) baker(baked chan<- cake) { | |
| for i := 0; i < s.Cakes; i++ { | |
| c := cake(i) | |
| if s.Verbose { | |
| fmt.Println("baking", c) | |
| } | |
| work(s.BakeTime, s.BakeStdDev) | |
| baked <- c | |
| } | |
| close(baked) | |
| } | |
| func (s *Shop) icer(iced chan<- cake, baked <-chan cake) { | |
| for c := range baked { | |
| if s.Verbose { | |
| fmt.Println("icing", c) | |
| } | |
| work(s.IceTime, s.IceStdDev) | |
| iced <- c | |
| } | |
| } | |
| func (s *Shop) inscriber(iced <-chan cake) { | |
| for i := 0; i < s.Cakes; i++ { | |
| c := <-iced | |
| if s.Verbose { | |
| fmt.Println("inscribing", c) | |
| } | |
| work(s.InscribeTime, s.InscribeStdDev) | |
| if s.Verbose { | |
| fmt.Println("finished", c) | |
| } | |
| } | |
| } | |
| // Work runs the simulation 'runs' times. | |
| func (s *Shop) Work(runs int) { | |
| for run := 0; run < runs; run++ { | |
| baked := make(chan cake, s.BakeBuf) | |
| iced := make(chan cake, s.IceBuf) | |
| go s.baker(baked) | |
| for i := 0; i < s.NumIcers; i++ { | |
| go s.icer(iced, baked) | |
| } | |
| s.inscriber(iced) | |
| } | |
| } | |
| // work blocks the calling goroutine for a period of time | |
| // that is normally distributed around d | |
| // with a standard deviation of stddev. | |
| func work(d, stddev time.Duration) { | |
| delay := d + time.Duration(rand.NormFloat64()*float64(stddev)) | |
| time.Sleep(delay) | |
| } |