按顺序从golang频道读取



我正在尝试通过go中的通道实现并行处理和通信。

我基本上尝试解决的是并行处理特定的数据,并获得顺序=>引入Chunk类型的结果(见下文)。

我只是为每个块处理创建一个新的通道,并将它们保存在slice =>中,期望在之后迭代它们时被排序。

程序的简化版本是(https://play.golang.org/p/RVtDGgUVCV):

package main
import (
    "fmt"
)
type Chunk struct {
    from int
    to   int
}
func main() {
    chunks := []Chunk{
        Chunk{
            from: 0,
            to:   2,
        },
        Chunk{
            from: 2,
            to:   4,
        },
    }
    outChannels := [](<-chan struct {
        string
        error
    }){}
    for _, chunk := range chunks {
        outChannels = append(outChannels, processChunk(&chunk))
    }
    for _, outChannel := range outChannels {
        for out := range outChannel {
            if out.error != nil {
                fmt.Printf("[ERROR] %s", out.error)
                return
            }
            fmt.Printf("[STDOUT] %s", out.string)
        }
    }
}
func processChunk(c *Chunk) <-chan struct {
    string
    error
} {
    outChannel := make(chan struct {
        string
        error
    })
    go func() {
        outChannel <- struct {
            string
            error
        }{fmt.Sprintf("from: %d to: %dn", c.from, c.to), nil}
        close(outChannel)
    }()
    return outChannel
}
我看到的输出是:
[STDOUT] from: 2 to: 4
[STDOUT] from: 2 to: 4

我希望看到的是:

[STDOUT] from: 0 to: 2
[STDOUT] from: 2 to: 4

我在这里做错了什么?我看不出来

问题出现在main的第一个for循环中。当您使用for range循环时,循环变量(这里的chunk)被创建一次,并在每次迭代中分配每个切片元素的副本。

当你调用processChunk(&chunk)时,你传递了这个循环变量的地址,这个变量的值随着每次迭代而改变。因此,函数processChunk总是最终处理chunks循环中的最后一项,因为这是*chunk在for循环结束后指向的。

修复,使用切片索引:

for i := 0; i < len(chunks); i++ {
    // pass chunk objects by indexing chunks
    outChannels = append(outChannels, processChunk(&chunks[i]))
}

修复代码:https://play.golang.org/p/A1_DtkncY_

您可以在这里阅读更多关于range的信息

最新更新