New to Go. I'm attempting to code an "assembly line" where multiple functions act like workers and pass some data structure to each other down the line, each doing something to the data structure.
type orderStruct struct {
orderNum,capacity int
orderCode uint64
box [9]int
}
func position0(in chan orderStruct){
order := <-in
if((order.orderCode<<63)>>63 == 1){
order.box[order.capacity] = 1
order.capacity += 1
}
fmt.Println(" filling box {", order.orderNum, order.orderCode, order.box, order.capacity, "} at position 0")
}
func startOrder(in chan orderStruct){
order := <-in
fmt.Printf("
Start an empty box for customer order number %d , request number %d
", order.orderNum, order.orderCode)
fmt.Println(" starting box {", order.orderNum, order.orderCode, order.box, order.capacity, "}")
d := make(chan orderStruct,1)
go position0(d)
d <- order
}
func main() {
var orders [10]orderStruct
numOrders := len(os.Args)-1
var x int
for i := 0; i < numOrders; i++{
x, _ = strconv.Atoi(os.Args[i+1])
orders[i].orderCode = uint64(x)
orders[i].orderNum = i+1
orders[i].capacity = 0
for j := 0; j < 9; j++{
orders[i].box[j] = 0
}
c := make(chan orderStruct)
go startOrder(c)
c <- orders[i]
}
}
So basically the issue I'm having is that the print statements in startOrder() execute fine, but when I try to pass the struct to position0(), nothing is printed. Am I misunderstanding how channels work?
I've attempted to re-write what you've written to work properly. You can run it on the playground
The main differences are
wg.Add(1); go startOrders(c, wg)
code)Here is the code
package main
import (
"fmt"
"sync"
)
type orderStruct struct {
orderNum, capacity int
orderCode uint64
box [9]int
}
func position0s(in chan orderStruct, wg *sync.WaitGroup) {
defer wg.Done()
for order := range in {
if (order.orderCode<<63)>>63 == 1 {
order.box[order.capacity] = 1
order.capacity += 1
}
fmt.Println(" filling box {", order.orderNum, order.orderCode, order.box, order.capacity, "} at position 0")
}
}
func startOrders(in chan orderStruct, wg *sync.WaitGroup) {
defer wg.Done()
d := make(chan orderStruct)
wg.Add(1)
go position0s(d, wg)
for order := range in {
fmt.Printf("
Start an empty box for customer order number %d , request number %d
", order.orderNum, order.orderCode)
fmt.Println(" starting box {", order.orderNum, order.orderCode, order.box, order.capacity, "}")
d <- order
}
close(d)
}
func main() {
var orders [10]orderStruct
numOrders := 4
var x int = 10
wg := new(sync.WaitGroup)
c := make(chan orderStruct)
wg.Add(1)
go startOrders(c, wg)
for i := 0; i < numOrders; i++ {
orders[i].orderCode = uint64(x)
orders[i].orderNum = i + 1
orders[i].capacity = 0
for j := 0; j < 9; j++ {
orders[i].box[j] = 0
}
c <- orders[i]
}
close(c)
wg.Wait()
}
Pipelines are a great place to start when learning to program concurrently in Go. Nick Craig-Wood's answer provides a working solution to this specific challenge.
There is a whole range of other ways to use concurrency in Go. Broadly, there are three categories divided according to what is being treated as concurrent:
Functional decomposition - Creating pipelines of several functions is a good way to get started - and is your question's topic. It's quite easy to think about and quite productive. However, if it progresses to truly parallel hardware, it's quite hard to balance the load well. Everything goes at the speed of the slowest pipeline stage.
Geometric decomposition - Dividing the data up into separate regions that can be processed independently (or without too much communication). Grid-based systems are popularly used in certain domains of scientific high-performance computing, such as weather-forecasting.
Farming - Identifying how the work to be done can be chopped into (a large number of) tasks and these tasks can be allocated to 'workers' one by one until all are completed. Often, the number of tasks far exceeds the number of workers. This category includes all the so-called 'embarrassingly parallel' problems (embarrassing because if you fail to get your high-performance system to give linear speed-up, you look a bit daft).
I could add a fourth category of hybrids of several of the above.
There is quite a lot of literature about this, including much from the days of Occam programming in the '80s and '90s. Go and Occam both use CSP message passing so the issues are similar. I would single out the helpful book Practical Parallel Processing: An introduction to problem solving in parallel (Chalmers and Tidmus 1996).