您的位置:首页 > 编程语言 > Go语言

Golang关于channel传递引用引发的坑

2018-01-30 00:00 274 查看
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), 所以通道第一次接收的值就已经改变了, 因为我们传递的是引用,不是值类型。

解决方案呢就是加锁 或者新变量拷贝。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  go引用类型