php小編魚仔為您揭示一個關于切片的問題:為什么通過通道和 goroutine 寫入切片最終為空?在Go語言中,通道和 goroutine 是并發編程的重要工具,但在某些情況下,使用它們寫入切片可能會出現意外結果。本文將詳細解釋這個問題的原因,并提供解決方案,幫助您更好地理解和處理這種情況。
問題內容
我運行這個函數:
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) }
登錄后復制
但最終,我的 vertices
切片是空的:
func doublecheckvertices(vertices []vertex) () { // here i notice that `vertices` slice is actually empty :( }
登錄后復制
返回 writer
的函數是這樣的:
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 }
登錄后復制
任何人都可以幫我弄清楚為什么我的 vertices
切片最終是空的嗎?
日志
日志表明 vertices
切片實際上已填充。但由于某種原因,傳遞給doublecheckvertices
時為空。
vertices = append(vertices, a) // This Log shows the slice is actually filled out: fmt.Printf("vertices len() is %v\n", len(vertices))
登錄后復制
解決方法
這看起來類似于“將切片作為函數參數傳遞,并修改原始切片”
如果您希望 goroutine 修改您在外部創建的切片,則需要一個指向該切片的指針:
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 }
登錄后復制