Golang Producer Consumer pattern ensure limitations

113 views Asked by At

I have code that implemented a producer consumer pattern in Golang, where given a list of resources (lunch), concurrently allocate resources to consumer Goroutines.

package main

import (
    "fmt"
    "log"
)

// given a list of recourses, simulates
// the concurrent allocation of recourses to consumer Goroutines.

// Signal channel: var signal chan struct{} = make(chan struct{})
// is a channel to synchronize Goroutines, not to send data.

// the number consumers
const consumerCount = 10

// types of resources to pass to consumers
var foodCourses = []string{
    "Caprese Salad",
    "Spaghetti Carbonara",
    "Vanilla Panna Cotta",
}

// Producer
func serveLunch(course string, out chan<- string, done <-chan struct{}) {
    // continuously send the course to the channel
    for { // infinite whilte true loop
        select {
        case out <- course:
        case <-done:
            // when done is closed,
            // it has a zero value of struct{} and the case is selected
            return
        }
    }
}

// Consumer
func takeLunch(name string, in []chan string, done chan<- struct{}) {
    for _, ch := range in {
        log.Printf("%s eats %s.\n", name, <-ch)
    }
    // this is same pattern as BlockingChannel exercise
    done <- struct{}{} // signal that this consumer is done
}

// use slice of channels as a queue to hold the lunches
// which are produced and consumed concurrently
func main() {
    log.Printf("Welcome to the conference lunch! Serving %d attendees.\n",
        consumerCount)
    var courses []chan string          // slice of channels to hold the lunches
    doneEating := make(chan struct{})  // signal channel
    doneServing := make(chan struct{}) // signal channel
    for _, c := range foodCourses {
        ch := make(chan string)
        courses = append(courses, ch)     // append lunch to the slice of channels queue
        go serveLunch(c, ch, doneServing) // current course string, single lunch channel, signal channel
        // one server per course
    }
    for i := 0; i < consumerCount; i++ {
        name := fmt.Sprintf("Attendee %d", i)
        go takeLunch(name, courses, doneEating) // name string, slice of channels, signal channel
    }

    for i := 0; i < consumerCount; i++ {
        <-doneEating // wait for all consumers to finish
    }
    close(doneServing) // close the signal channel to stop the producer
}

output:

2023/06/10 15:33:28 Welcome to the conference lunch! Serving 10 attendees.
2023/06/10 15:33:28 Attendee 8 eats Caprese Salad.
2023/06/10 15:33:28 Attendee 4 eats Caprese Salad.
2023/06/10 15:33:28 Attendee 5 eats Caprese Salad.
2023/06/10 15:33:28 Attendee 3 eats Caprese Salad.
2023/06/10 15:33:28 Attendee 3 eats Spaghetti Carbonara.
2023/06/10 15:33:28 Attendee 3 eats Vanilla Panna Cotta.
2023/06/10 15:33:28 Attendee 0 eats Caprese Salad.
2023/06/10 15:33:28 Attendee 0 eats Spaghetti Carbonara.
2023/06/10 15:33:28 Attendee 0 eats Vanilla Panna Cotta.
2023/06/10 15:33:28 Attendee 9 eats Caprese Salad.
2023/06/10 15:33:28 Attendee 9 eats Spaghetti Carbonara.
2023/06/10 15:33:28 Attendee 9 eats Vanilla Panna Cotta.
2023/06/10 15:33:28 Attendee 1 eats Caprese Salad.
2023/06/10 15:33:28 Attendee 2 eats Caprese Salad.
2023/06/10 15:33:28 Attendee 6 eats Caprese Salad.
2023/06/10 15:33:28 Attendee 7 eats Caprese Salad.
2023/06/10 15:33:28 Attendee 8 eats Spaghetti Carbonara.
2023/06/10 15:33:28 Attendee 4 eats Spaghetti Carbonara.
2023/06/10 15:33:28 Attendee 5 eats Spaghetti Carbonara.
2023/06/10 15:33:28 Attendee 1 eats Spaghetti Carbonara.
2023/06/10 15:33:28 Attendee 1 eats Vanilla Panna Cotta.
2023/06/10 15:33:28 Attendee 6 eats Spaghetti Carbonara.
2023/06/10 15:33:28 Attendee 6 eats Vanilla Panna Cotta.
2023/06/10 15:33:28 Attendee 2 eats Spaghetti Carbonara.
2023/06/10 15:33:28 Attendee 2 eats Vanilla Panna Cotta.
2023/06/10 15:33:28 Attendee 7 eats Spaghetti Carbonara.
2023/06/10 15:33:28 Attendee 7 eats Vanilla Panna Cotta.
2023/06/10 15:33:28 Attendee 8 eats Vanilla Panna Cotta.
2023/06/10 15:33:28 Attendee 4 eats Vanilla Panna Cotta.
2023/06/10 15:33:28 Attendee 5 eats Vanilla Panna Cotta.

My question is: in the code above, how does it ensure that each attendee ONLY consumes 3 lunches and ONLY 1 of each foodCourse?

Update Nov 6th, 2023: I figured it out. See picture below for my analysis. enter image description here

0

There are 0 answers