【轉】Golang關於channel傳遞引用引發的坑


原文: https://studygolang.com/articles/12310/comment/17923

--------------------------------------------------------------------------------------

 Time won't go back I won't turn back.

時光不會倒着走,我也不會再回頭。

 其實這個問題其實是出現在引用類型( 此處是slice )上, 這個是 slice 的數據結構,它很簡單,一個指向真實 array 地址的指針 ptr ,slice 的長度 len 和容量 cap 。

 結構圖解1

每次cap改變的時候指向array內存的指針都在變化, 在實際使用中,我們最好事先預期好一個cap,這樣在使用append的時候可以避免反復重新分配內存復制之前的數據,減少不必要的性能消耗。

現在上實例,來看看坑所在:

package main import "fmt" import "time" func main() { ch := make(chan []byte, 10) go func() { for { select { case data := <-ch: fmt.Println(string(data)) } } }() data := make([]byte, 0, 32) data = append(data, []byte("bbbbbbbbbb")...) ch <- data // fmt.Printf("%p\n", data) data = data[:0] // fmt.Printf("%p\n", data) data = append(data, []byte("aaa")...) ch <- data time.Sleep(time.Second * 5) } 

預測的運行結果:

bbbbbbbbbb

aaa

 

但是肯定是有坑的

前面新起了一個協程來等待通道接受信息, 主進程繼續執行, 當data傳遞給了通道之后, 立刻修改了data指向數組的值(第二次append), 所以通道第一次接收的值就已經改變了, 因為我們傳遞的是引用,不是值類型。

解決方案呢就是加鎖 或者新變量拷貝。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM