同时遍历两个集合

In Go, what is the best way to iterate through 2 collections concurrently?

In my program, I have one function that creates two arrays, and another function that need to iterate over them simultaneously (in each iteration access the I'th element in both of the arrays).

If I had a single input, I would have created a channel in the first function (instead of an array), and used range loops to iterate over it from various goroutines.

In this case, is there a simpler solution than creating a channel of indexes and using it to access the arrays?

func main() {
    // Prepare two arrays.
    arrA := [12]int{1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144}
    arrB := arrA

    // Create a channel with the indexes.
    c := make(chan int, len(arrA))
    for i := range arrA {
        c <- i
    }
    close(c)

    poolSize := 3
    var wg sync.WaitGroup
    wg.Add(poolSize)

    for i := 1; i <= poolSize; i++ {
        go func() {
            defer wg.Done()
            for j := range c {
                fmt.Printf("%v == %v
", arrA[j], arrB[j])
            }
        }()
    }

    wg.Wait()
}

There's a saying in go

"Don't communicate by sharing memory, share memory by communicating"

It basically boils down to;

"Don't share state across 2 goroutines, instead pass the values needed between the routines, using channels"

It may be a biproduct of your simplified example, but instead of passing the indicies, why can't you limit the scope of the arrA and arrB to be inside a single goroutine, some kind of producer or generator that will send the values. The receiver of those values can do the work on them, in this case equal comparisons.

type pair struct {
    a, b int
}

c := make(chan pair, len(arrA))
for i := range arrA {
    c <- pair{a: arrA[i], b: arrB[i]}
}
close(c)

poolSize := 3
var wg sync.WaitGroup
wg.Add(poolSize)

for _ := range poolSize {
    go func() {
        defer wg.Done()
        for p := range c {
            fmt.Printf("%v == %v
", p.a, p.b)
        }
    }
}

This might seem like a trivially small change but the benefits are:

  1. Isolation: you are limiting the scope of accessors to arrA and arrB to a single producing goroutine, limit the scope for race conditions / complex logic / bugs later on in the code.
  2. Reuse: you can reuse the code functions that consume a chan pair elsewhere in the codebase as they do not directly access the values in specific arrays, instead are passed all the values they need.

To extend this; assuming that you only need the value from arrB and do not care about the index, then you should send that value on the channel, and remove the need for the pair type.