drtohng5613
2018-07-02 13:46
浏览 135
已采纳

同时遍历两个集合

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()
}
  • 写回答
  • 好问题 提建议
  • 关注问题
  • 收藏
  • 邀请回答

1条回答 默认 最新

  • doudi2005 2018-07-02 13:59
    已采纳

    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.

    已采纳该答案
    评论
    解决 无用
    打赏 举报

相关推荐 更多相似问题