mirror of
https://github.com/gopl-zh/gopl-zh.github.com.git
synced 2025-09-12 22:52:05 +00:00
good good study, day day up!
This commit is contained in:
89
vendor/gopl.io/ch8/cake/cake.go
generated
vendored
Normal file
89
vendor/gopl.io/ch8/cake/cake.go
generated
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
// 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)
|
||||
}
|
74
vendor/gopl.io/ch8/cake/cake_test.go
generated
vendored
Normal file
74
vendor/gopl.io/ch8/cake/cake_test.go
generated
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
package cake_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"gopl.io/ch8/cake"
|
||||
)
|
||||
|
||||
var defaults = cake.Shop{
|
||||
Verbose: testing.Verbose(),
|
||||
Cakes: 20,
|
||||
BakeTime: 10 * time.Millisecond,
|
||||
NumIcers: 1,
|
||||
IceTime: 10 * time.Millisecond,
|
||||
InscribeTime: 10 * time.Millisecond,
|
||||
}
|
||||
|
||||
func Benchmark(b *testing.B) {
|
||||
// Baseline: one baker, one icer, one inscriber.
|
||||
// Each step takes exactly 10ms. No buffers.
|
||||
cakeshop := defaults
|
||||
cakeshop.Work(b.N) // 224 ms
|
||||
}
|
||||
|
||||
func BenchmarkBuffers(b *testing.B) {
|
||||
// Adding buffers has no effect.
|
||||
cakeshop := defaults
|
||||
cakeshop.BakeBuf = 10
|
||||
cakeshop.IceBuf = 10
|
||||
cakeshop.Work(b.N) // 224 ms
|
||||
}
|
||||
|
||||
func BenchmarkVariable(b *testing.B) {
|
||||
// Adding variability to rate of each step
|
||||
// increases total time due to channel delays.
|
||||
cakeshop := defaults
|
||||
cakeshop.BakeStdDev = cakeshop.BakeTime / 4
|
||||
cakeshop.IceStdDev = cakeshop.IceTime / 4
|
||||
cakeshop.InscribeStdDev = cakeshop.InscribeTime / 4
|
||||
cakeshop.Work(b.N) // 259 ms
|
||||
}
|
||||
|
||||
func BenchmarkVariableBuffers(b *testing.B) {
|
||||
// Adding channel buffers reduces
|
||||
// delays resulting from variability.
|
||||
cakeshop := defaults
|
||||
cakeshop.BakeStdDev = cakeshop.BakeTime / 4
|
||||
cakeshop.IceStdDev = cakeshop.IceTime / 4
|
||||
cakeshop.InscribeStdDev = cakeshop.InscribeTime / 4
|
||||
cakeshop.BakeBuf = 10
|
||||
cakeshop.IceBuf = 10
|
||||
cakeshop.Work(b.N) // 244 ms
|
||||
}
|
||||
|
||||
func BenchmarkSlowIcing(b *testing.B) {
|
||||
// Making the middle stage slower
|
||||
// adds directly to the critical path.
|
||||
cakeshop := defaults
|
||||
cakeshop.IceTime = 50 * time.Millisecond
|
||||
cakeshop.Work(b.N) // 1.032 s
|
||||
}
|
||||
|
||||
func BenchmarkSlowIcingManyIcers(b *testing.B) {
|
||||
// Adding more icing cooks reduces the cost of icing
|
||||
// to its sequential component, following Amdahl's Law.
|
||||
cakeshop := defaults
|
||||
cakeshop.IceTime = 50 * time.Millisecond
|
||||
cakeshop.NumIcers = 5
|
||||
cakeshop.Work(b.N) // 288ms
|
||||
}
|
Reference in New Issue
Block a user