Before we try to solve the problem, let's first formulate what we want to achieve:
- Create a channel orderChannel that accepts all orders.
- Launch the required number of cashier goroutines that accept limited numbers of orders from orderChannel.
- Start putting all orders into orderChannel.
Let's look at one possible solution that tries to solve the cashier problem using the preceding steps:
// wichan.go package main import ( "fmt" "sync" ) func cashier(cashierID int, orderChannel <-chan int, wg *sync.WaitGroup) { // Process orders upto limit. for ordersProcessed := 0; ordersProcessed < 10; ordersProcessed++ { // Retrieve order from orderChannel orderNum := <-orderChannel // Cashier is ready to serve! fmt.Println("Cashier ", cashierID, "Processing order", orderNum, "Orders Processed", ordersProcessed) wg.Done() } } func main() { var wg sync.WaitGroup wg.Add(30) ordersChannel := make(chan int) for i := 0; i < 3; i++ { // Start the three cashiers func(i int) { go cashier(i, ordersChannel, &wg) }(i) } // Start adding orders to be processed. for i := 0; i < 30; i++ { ordersChannel <- i } wg.Wait() }
On running the preceding code with -race flag, we can see that the code ran without any data races:
$ go run -race wichan.go Cashier 2 Processing order 2 Orders Processed 0 Cashier 2 Processing order 3 Orders Processed 1 Cashier 0 Processing order 0 Orders Processed 0 Cashier 1 Processing order 1 Orders Processed 0 ... Cashier 0 Processing order 27 Orders Processed 9
The code is quite straightforward, is easy to parallelize, and works well without causing any data races.