【转】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), 所以通道第一次接收的值就已经改变了, 因为我们传递的是引用,不是值类型。

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

 

转载于:https://www.cnblogs.com/oxspirt/p/11277544.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值