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

huangapple go评论89阅读模式
英文:

Writing to a slice by a channel and a goroutine: why slice is eventually empty

问题

我运行了这个函数:

func Run() () {
	// 这个切片将通过通道和 goroutine 填充。
	vertices := make([]Vertex, 0)

	var wg sync.WaitGroup

	// 获取一个写入器来填充顶点。
	writer := Writer(&wg, vertices)

	// 运行一个任意的逻辑来向写入器发送数据。
	Logic(writer)

	// 停止写入器在通道上的读取。
	close(writer)

	// 等待写入完成。
	wg.Wait()

	// 检查顶点切片是否实际上已经填充。
	DoublecheckVertices(vertices)
}

但最终,我的 vertices 切片是空的:

func DoublecheckVertices(vertices []Vertex) () {
	// 在这里我注意到 `vertices` 切片实际上是空的 :(

}

返回 writer 的函数大致如下:

func Writer(wg *sync.WaitGroup, vertices []Vertex) (chan<- []*Triangle3) {
	// 外部代码向该通道写入。
	// 这个 goroutine 读取通道并写入 vertices。
	writer := make(chan []*Triangle3)

	// 通过 goroutine 进行写入。
	wg.Add(1)
	go func() {
		defer wg.Done()

        a := Vertex{}

		// 从通道读取并将其写入 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
}

有人可以帮我找出为什么我的 vertices 切片最终为空吗?

日志

日志显示 vertices 切片实际上已经填充。但出于某种原因,在传递给 DoublecheckVertices 函数时它是空的。

				vertices = append(vertices, a)
				// 这个日志显示切片实际上已经填充:
				fmt.Printf("vertices len() is %v\n", len(vertices))
英文:

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 eventually, my vertices slice is empty:

func DoublecheckVertices(vertices []Vertex) () {
	// Here I notice that `vertices` slice is actually empty :(

}

The function which returns the writer is something 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 anybody help me with figuring out why my vertices slice is eventually empty?

Logs

Logs indicate that the vertices slice is actually filled out. But for some reason, it's empty when it's 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))

答案1

得分: 1

这似乎与"将切片作为函数参数传递,并修改原始切片"类似。

如果你希望你的goroutine修改在外部创建的切片,你需要一个指向该切片的指针:

func Writer(wg *sync.WaitGroup, vertices *[]Vertex) (chan<- []*Triangle3) {
    // 外部代码向该通道写入数据。
    // 这个goroutine读取通道并将数据写入vertices。
    writer := make(chan []*Triangle3)

    // 由一个goroutine进行写入。
    wg.Add(1)
    go func() {
        defer wg.Done()

        a := Vertex{}

        // 从通道读取数据并将其写入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
}
英文:

That seems similar to "Pass slice as function argument, and modify the original slice"

If you want your goroutine to modify the slice you created outside, you would need a pointer to that slice:

func Writer(wg *sync.WaitGroup, vertices *[]Vertex) (chan&lt;- []*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)  &lt;=====
            }
        }
    }()

    return writer
}

huangapple
  • 本文由 发表于 2023年1月15日 16:52:03
  • 转载请务必保留本文链接:https://go.coder-hub.com/75123909.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定