Home  >  Article  >  Backend Development  >  Writing to slices via channels and goroutines: why slices end up empty

Writing to slices via channels and goroutines: why slices end up empty

王林
王林forward
2024-02-11 18:50:081213browse

通过通道和 goroutine 写入切片:为什么切片最终为空

php Xiaobian Yuzai reveals a question about slicing for you: Why does the slice written through the channel and goroutine end up being empty? In Go, channels and goroutines are important tools for concurrent programming, but in some cases, using them to write slices can have unexpected results. This article will explain the cause of this problem in detail and provide solutions to help you better understand and deal with this situation.

Question content

I run this function:

func run() () {
    // this slice is going to be filled out by a channel and goroutine.
    vertices := make([]vertex, 0)

    var wg sync.waitgroup

    // obtain a writer to fill out the vertices.
    writer := writer(&wg, vertices)

    // run an arbitrary logic to send data to writer.
    logic(writer)

    // stop the writer reading on the channel.
    close(writer)

    // wait for the write to complete.
    wg.wait()

    // see if vertices slice is actually filled out.
    doublecheckvertices(vertices)
}

But in the end, my vertices slice is empty:

func doublecheckvertices(vertices []vertex) () {
    // here i notice that `vertices` slice is actually empty :(

}

The function that returns writer is like this:

func writer(wg *sync.waitgroup, vertices []vertex) (chan<- []*triangle3) {
    // external code writes to this channel.
    // this goroutine reads the channel and writes to vertices.
    writer := make(chan []*triangle3)

    // write by a goroutine.
    wg.add(1)
    go func() {
        defer wg.done()

        a := vertex{}

        // read from the channel and write them to vertices.
        for ts := range writer {
            for _, t := range ts {
                a.x = float32(t.v[0].x)
                a.y = float32(t.v[0].y)
                a.z = float32(t.v[0].z)
                vertices = append(vertices, a)
            }
        }
    }()

    return writer
}

Can anyone help me figure out why my vertices slice ends up empty?

log

The log shows that the vertices slice is actually populated. But for some reason it is empty when passed to doublecheckvertices.

                vertices = append(vertices, a)
                // This Log shows the slice is actually filled out:
                fmt.Printf("vertices len() is %v\n", len(vertices))

Workaround

This looks similar to "Pass the slice as a function parameter and modify the original slice"

If you want the goroutine to modify a slice you created externally, you need a pointer to the slice:

func Writer(wg *sync.WaitGroup, vertices *[]Vertex) (chan<- []*Triangle3) {
    // External code writes to this channel.
    // This goroutine reads the channel and writes to vertices.
    writer := make(chan []*Triangle3)

    // Write by a goroutine.
    wg.Add(1)
    go func() {
        defer wg.Done()

        a := Vertex{}

        // Read from the channel and write them to vertices.
        for ts := range writer {
            for _, t := range ts {
                a.X = float32(t.V[0].X)
                a.Y = float32(t.V[0].Y)
                a.Z = float32(t.V[0].Z)
                *vertices = append(*vertices, a)  <=====
            }
        }
    }()

    return writer
}

The above is the detailed content of Writing to slices via channels and goroutines: why slices end up empty. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:stackoverflow.com. If there is any infringement, please contact admin@php.cn delete