【问题标题】:Iterate through two collections concurrently同时遍历两个集合
【发布时间】:2018-12-10 18:32:04
【问题描述】:

在 Go 中,同时遍历 2 个集合的最佳方法是什么?

在我的程序中,我有一个函数创建两个数组,另一个函数需要同时迭代它们(在每次迭代中访问两个数组中的第 I 个元素)。

如果我只有一个输入,我会在第一个函数中创建一个通道(而不是一个数组),并使用范围循环从各种 goroutine 对其进行迭代。

在这种情况下,有没有比创建索引通道并使用它来访问数组更简单的解决方案?

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\n", arrA[j], arrB[j])
            }
        }()
    }

    wg.Wait()
}

【问题讨论】:

    标签: arrays go channel


    【解决方案1】:

    go中有一句话

    “不要通过共享内存进行通信,通过通信来共享内存”

    它基本上归结为;

    “不要在 2 个 goroutine 之间共享状态,而是使用通道在例程之间传递所需的值”

    它可能是您简化示例的副产品,但是您为什么不能将 arrAarrB 的范围限制在单个 goroutine、某种生产者或生成器中,而不是传递索引这将发送值。这些值的接收者可以对它们进行处理,在这种情况下是相等的比较。

    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\n", p.a, p.b)
            }
        }
    }
    

    这似乎是一个微不足道的小改动,但好处是:

    1. 隔离:您将 arrA 和 arrB 的访问器范围限制为单个生产 goroutine,稍后在代码中限制竞争条件/复杂逻辑/错误的范围。
    2. 重用:您可以在代码库的其他地方重用使用chan pair 的代码函数,因为它们不直接访问特定数组中的值,而是传递它们需要的所有值。

    扩展它;假设您只需要来自arrB 的值并且不关心索引,那么您应该在通道上发送该值,并且不需要pair 类型。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-09-06
      • 1970-01-01
      • 2016-11-16
      • 2020-03-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多