Golang關於channel傳遞引用引起的坑

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

時光不會倒着走,我也不會再回頭。數據結構

    其實應該理解爲是slice的坑致使。 app

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

 結構圖解1指針

每次cap改變的時候指向array內存的指針都在變化, 在實際使用中,咱們最好事先預期好一個cap,這樣在使用append的時候能夠避免反覆從新分配內存複製以前的數據,減小沒必要要的性能消耗。code

如今上實例,來看看坑所在:協程

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內存

aaastring

 

可是確定是有坑的

前面新起了一個協程來等待通道接受信息, 主進程繼續執行, 當data第一次傳遞給了通道以後, (第二次append)馬上修改了data指向數組的值(aaabbbbbbb),要注意的地方還有data = data[:0],   因此通道第一次接收的值就已經改變了, 由於咱們傳遞的是引用,不是值類型。

若是在Append以前sleep, 那麼確定輸出的是bbbbbb 。

 

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

相關文章
相關標籤/搜索