博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Golang关于channel传递引用引发的坑
阅读量:7064 次
发布时间:2019-06-28

本文共 976 字,大约阅读时间需要 3 分钟。

hot3.png

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

时光不会倒着走,我也不会再回头。

    其实应该理解为是slice的坑导致。 

    这个问题其实是出现在引用类型( 此处是slice )上, 这个是 slice 的数据结构,它很简单,一个指向真实 array 地址的指针 ptr ,slice 的长度 len 和容量 cap 。

30153002_0EGT.png

 结构图解1

30153002_l0gl.png

每次cap改变的时候指向array内存的指针都在变化, 在实际使用中,我们最好事先预期好一个cap,这样在使用append的时候可以避免反复重新分配内存复制之前的数据,减少不必要的性能消耗。

现在上实例,来看看坑所在:

package mainimport "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

 

但是肯定是有坑的

152649_M1Mu_2271515.png

前面新起了一个协程来等待通道接受信息, 主进程继续执行, 当data第一次传递给了通道之后, (第二次append)立刻修改了data指向数组的值(aaabbbbbbb),要注意的地方还有data = data[:0],   所以通道第一次接收的值就已经改变了, 因为我们传递的是引用,不是值类型。

如果在Append之前sleep, 那么肯定输出的是bbbbbb 。

 

解决方案呢就是加锁 或者新变量拷贝。

 

 

 

 

转载于:https://my.oschina.net/90design/blog/1615562

你可能感兴趣的文章
Understanding memory usage on Linux
查看>>
Oracle浅谈之逻辑体系第一回
查看>>
RequireJS 基础学习
查看>>
MyEclipse10安装PyDev插件
查看>>
C++ 0x 之左值与右值、右值引用、移动语义、传导模板
查看>>
KeyShot中的环境光遮蔽该怎么进行使用
查看>>
GIT 不常用的实用命令
查看>>
一个简单的替换Emoji表情字符的方法
查看>>
Server should be SSL-aware but has no certificate
查看>>
ubuntu16.04安装mysql并配置远程访问
查看>>
poj 选择客栈
查看>>
加上线程池后Netty的Reacotr模型,两张图说明问题
查看>>
notepad++中emmet插件的使用
查看>>
Notepad++对.tpl默认打开且高亮显示HTML代码
查看>>
How The Kernel Manages Your Memory
查看>>
LINUX的学习路上的锁锁碎碎
查看>>
spring MVC 3.1 forword/redirect
查看>>
移动端压缩上传图片
查看>>
利用哈希表实现数组的去重以及利用delete批量删除数组元素
查看>>
Maven 启动找不到 Launcher 的问题
查看>>