Skip to content

Instantly share code, notes, and snippets.

@mattetti
Created June 3, 2016 16:58
Show Gist options
  • Save mattetti/2c7b67cd9c2e288b6c41bc6a23759137 to your computer and use it in GitHub Desktop.
Save mattetti/2c7b67cd9c2e288b6c41bc6a23759137 to your computer and use it in GitHub Desktop.
// example of parallelism
package main
import (
"flag"
"fmt"
"io"
"os"
"sync"
"time"
"github.com/hybridgroup/gobot/platforms/firmata/client"
"github.com/tarm/goserial"
)
var (
board *client.Client
ledFlag = flag.Bool("led", false, "don't connect to the board")
iterationFlag = flag.Int("iteration", 5, "iteration to run")
jcFlag = flag.Bool("jc", false, "third chef?")
)
var logs = map[time.Time]string{}
type order struct {
dish string
num int
duration time.Duration
}
func newChef(name string, station int) *chef {
return &chef{station: station, name: name, mutex: &sync.Mutex{}}
}
type chef struct {
station int
name string
busyState bool
mutex *sync.Mutex
}
func (c *chef) isBusy() bool {
defer c.mutex.Unlock()
c.mutex.Lock()
return c.busyState
}
func (c *chef) busy(b bool) {
c.mutex.Lock()
c.busyState = b
c.mutex.Unlock()
}
func (c *chef) cook(o *order) {
if c.isBusy() {
fmt.Println("hold on!! ", c.name, "is already cooking!")
for c.isBusy() {
<-time.After(10 * time.Millisecond)
}
}
c.busy(true)
fmt.Printf("\t%s is cooking a %s (order %d)\n", c.name, o.dish, o.num)
if *ledFlag {
if err := board.DigitalWrite(c.station, 1); err != nil {
panic(err)
}
}
time.Sleep(o.duration)
logs[time.Now()] = fmt.Sprintf("%s cooked a %s", c.name, o.dish)
c.rest()
}
func (c *chef) rest() {
if *ledFlag {
if err := board.DigitalWrite(c.station, 0); err != nil {
panic(err)
}
}
// minimal rest required by law
fmt.Printf("\t\t*%s is resting*\n", c.name)
time.Sleep(100 * time.Millisecond)
c.busy(false)
}
func main() {
flag.Parse()
var sp io.ReadWriteCloser
var err error
if *ledFlag {
sp, err = serial.OpenPort(&serial.Config{Name: "/dev/cu.usbmodem1411", Baud: 57600})
if err != nil {
panic(err)
}
board = client.New()
}
fmt.Println("connecting.....")
if *ledFlag {
if err := board.Connect(sp); err != nil {
panic(err)
}
defer board.Disconnect()
resetLEDs()
}
chefs := []*chef{newChef("Alice", 2), newChef("Bob", 3)}
if *jcFlag {
chefs = append(chefs, newChef("Jean-Claude", 5))
}
orders := []*order{
{"Blanquette de veau", 0, 1500 * time.Millisecond},
{"Soupe à l'oignon", 1, 850 * time.Millisecond},
{"Quiche", 2, 550 * time.Millisecond},
{"Boeuf bourguignon", 3, 3000 * time.Millisecond},
{"Salade niçoise", 4, 800 * time.Millisecond},
{"Confit de canard", 5, 1900 * time.Millisecond},
{"Tarte tatin", 6, 3200 * time.Millisecond},
{"Ratatouille", 7, 850 * time.Millisecond},
{"Croque-monsieur", 8, 700 * time.Millisecond},
{"Jambon-beurre", 9, 700 * time.Millisecond},
}
startT := time.Now()
switch *iterationFlag {
case 1:
one(orders, chefs)
case 2:
two(orders, chefs)
case 3:
three(orders, chefs)
case 4:
four(orders, chefs)
case 5:
five(orders, chefs)
}
if *ledFlag {
if !*jcFlag {
if err := board.DigitalWrite(5, 0); err != nil {
panic(err)
}
} else {
// pins used on arduino 2,3,4
// pins used on ADK: 4,5,9
for i := 1; i < 11; i++ {
switch i {
/*
case 4, 5, 9:
v := (board.Pins()[i].Value + 1) % 2
if err = board.DigitalWrite(i, v); err != nil {
panic(err)
}
*/
default:
if err := board.DigitalWrite(i, 0); err != nil {
panic(err)
}
<-time.After(2 * time.Millisecond)
}
}
}
}
if err := board.DigitalWrite(4, 1); err != nil {
panic(err)
}
fmt.Printf("all done in %s, closing the kitchen\n", time.Since(startT))
fmt.Println("logs:")
for t, entry := range logs {
fmt.Printf("%s: %s\n", t, entry)
}
os.Exit(0)
}
// round robin, only 1 chef cooks everything :(
func one(orders []*order, chefs []*chef) {
for _, order := range orders {
for _, chef := range chefs {
if !chef.isBusy() {
chef.cook(order)
break
} else {
fmt.Println(".")
}
}
}
}
// exit right away because we aren't waiting
func two(orders []*order, chefs []*chef) {
for _, order := range orders {
for _, chef := range chefs {
if !chef.isBusy() {
go chef.cook(order)
break
} else {
fmt.Println(".")
}
}
}
}
/*
use a wait group to wait for the chefs to be done
try to send the order to a chef until one is available
ok, but confusing code
*/
func three(orders []*order, chefs []*chef) {
wg := &sync.WaitGroup{}
for _, order := range orders {
outterLoop:
for {
for _, chef := range chefs {
if !chef.isBusy() {
chef.cookAndYell(order, wg)
break outterLoop
}
}
}
}
wg.Wait()
}
func (c *chef) cookAndYell(o *order, wg *sync.WaitGroup) {
wg.Add(1)
if c.isBusy() {
fmt.Printf("\t%s is already cooking %s (order %d)\n", c.name, o.dish, o.num)
for c.isBusy() {
<-time.After(10 * time.Millisecond)
}
}
c.busy(true)
go func() {
fmt.Printf("\t%s is cooking a %s (order %d)\n", c.name, o.dish, o.num)
if *ledFlag {
if err := board.DigitalWrite(c.station, 0); err != nil {
panic(err)
}
}
time.Sleep(o.duration)
//logs[time.Now()] = fmt.Sprintf("%s cooked a %s", c.name, o.dish)
c.restAndYell(wg)
}()
}
func (c *chef) restAndYell(wg *sync.WaitGroup) {
if *ledFlag {
if err := board.DigitalWrite(c.station, 1); err != nil {
panic(err)
}
}
// minimal rest required by law
fmt.Printf("\t\t*%s is resting*\n", c.name)
time.Sleep(500 * time.Millisecond)
c.busy(false)
wg.Done()
}
/*
44444444444444444444444444444444444444444444444444
almost proper solution
*/
func four(orders []*order, chefs []*chef) {
orderWheel := make(chan *order)
for _, c := range chefs {
go func(c *chef) {
for o := range orderWheel {
c.cook(o)
}
}(c)
}
for _, order := range orders {
orderWheel <- order
}
close(orderWheel)
}
/*
55555555555555555555555
*/
func five(orders []*order, chefs []*chef) {
wg := &sync.WaitGroup{}
orderWheel := make(chan *order)
for _, c := range chefs {
wg.Add(1)
go func(c *chef) {
for o := range orderWheel {
c.cook(o)
}
wg.Done()
}(c)
}
for _, order := range orders {
orderWheel <- order
}
close(orderWheel)
wg.Wait()
}
func resetLEDs() {
for i := 2; i < 11; i++ {
if err := board.DigitalWrite(i, 0); err != nil {
panic(err)
}
}
time.Sleep(500 * time.Millisecond)
}
@jordanfowler
Copy link

👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment