美文网首页
golang通道中传递slice数据的入坑经验

golang通道中传递slice数据的入坑经验

作者: kingeasternsun | 来源:发表于2017-07-06 09:25 被阅读0次

背景

假设我们要开发生产者-消费者模型的代码,一个routine负责生产数据,一个routine负责消费数据,具体代码如下:

错误代码


type MsgStru struct {
    msg []int
}

var msgChan chan MsgStru

func sendMsg() {
    buf := make([]int, 10)
    for i := 0; i < 10; i++ {
        buf[0] = i
        tmp := MsgStru{msg: buf[:1]}
        fmt.Printf("send:%+v\n", tmp)
        msgChan <- tmp
    }
    fmt.Println("finish send")
}

func recvMsg() {
    for {
        tmp, _ := <-msgChan
        fmt.Printf("recv:%+v\n", tmp)
    }
}

func main() {

    msgChan = make(chan MsgStru, 10)
    go sendMsg()
    time.Sleep(1 * time.Second)
    recvMsg()

}

期望的输出应该是顺序打印0到9,但是实际打印呢?

send:{msg:[0]}
send:{msg:[1]}
send:{msg:[2]}
send:{msg:[3]}
send:{msg:[4]}
send:{msg:[5]}
send:{msg:[6]}
send:{msg:[7]}
send:{msg:[8]}
send:{msg:[9]}
finish send
recv:{msg:[9]}
recv:{msg:[9]}
recv:{msg:[9]}
recv:{msg:[9]}
recv:{msg:[9]}
recv:{msg:[9]}
recv:{msg:[9]}
recv:{msg:[9]}
recv:{msg:[9]}
recv:{msg:[9]}

接受到的数据都是数字9,这是为什么呢?

原因分析

首先看通道中数据的类型表示:

type MsgStru struct {
    msg []int
}

msg是一个slice,slice在go中是一个指针加长度,也就是说传入到通道中的是指向buf的指针,buf是一个全局变量,所以通道中的10个msg的数据都是指向buf的指针,当recvMsg准备读取数据的时候,buf中的数据此时变为了9,所以从通道中读取的10个msg都是9.

修改方案1

将全局slice改为局部slice

func sendMsg() {
    buf := make([]int, 10)
    for i := 0; i < 10; i++ {

        buf[0] = i

        tmpMsg := make([]int, 0)
        tmpMsg = append(tmpMsg, buf[:1]...)

        tmp := MsgStru{msg: tmpMsg}
        fmt.Printf("send:%+v\n", tmp)
        msgChan <- tmp
    }
    fmt.Println("finish send")
}

结果

send:{msg:[0]}
send:{msg:[1]}
send:{msg:[2]}
send:{msg:[3]}
send:{msg:[4]}
send:{msg:[5]}
send:{msg:[6]}
send:{msg:[7]}
send:{msg:[8]}
send:{msg:[9]}
finish send
recv:{msg:[0]}
recv:{msg:[1]}
recv:{msg:[2]}
recv:{msg:[3]}
recv:{msg:[4]}
recv:{msg:[5]}
recv:{msg:[6]}
recv:{msg:[7]}
recv:{msg:[8]}
recv:{msg:[9]}

修改方案2

将slice 改为array

type MsgStru struct {
    msg [2]int
}

var msgChan chan MsgStru

func sendMsg() {
    var buf [2]int
    for i := 0; i < 10; i++ {

        buf[0] = i

        tmp := MsgStru{msg: buf}
        fmt.Printf("send:%+v\n", tmp)
        msgChan <- tmp
    }
    fmt.Println("finish send")
}

结果

send:{msg:[0 0]}
send:{msg:[1 0]}
send:{msg:[2 0]}
send:{msg:[3 0]}
send:{msg:[4 0]}
send:{msg:[5 0]}
send:{msg:[6 0]}
send:{msg:[7 0]}
send:{msg:[8 0]}
send:{msg:[9 0]}
finish send
recv:{msg:[0 0]}
recv:{msg:[1 0]}
recv:{msg:[2 0]}
recv:{msg:[3 0]}
recv:{msg:[4 0]}
recv:{msg:[5 0]}
recv:{msg:[6 0]}
recv:{msg:[7 0]}
recv:{msg:[8 0]}
recv:{msg:[9 0]}

后记

之前一直在CSDN上写文章,后面会逐步转换到简书上,还请大家多多支持。

相关文章

  • golang通道中传递slice数据的入坑经验

    背景 假设我们要开发生产者-消费者模型的代码,一个routine负责生产数据,一个routine负责消费数据,具体...

  • golang slice的误解

    slice的介绍: 在golang的官方文档中,我们发现golang除了有array的数据还有一个slice,而a...

  • slice切片做函数参数

    首先要明确一点:slice作为函数参数是值传递. 再来分析一下golang中的切片slice底层的实现细节...

  • golang 从 map 获取值时的值拷贝问题

    实际场景 我们知道 golang 中,slice, map, channel 是引用类型,函数之间传递都是以值拷贝...

  • 深入理解Golang Slice

    深入理解Golang Slice 数据结构 slice的底层数据结构中的array是一个指针,指向的是一个Arra...

  • golang-slice

    最近在使用golang进行开发,使用slice的时候遇到了一些坑 slice:用来弥补数组的不足,称之为数组切片 ...

  • python中的可变对象/不可变对象和golang中的值变量/指

    对于golang,我们知道字符串,数组等是值变量,具有值传递的特性;slice,map等是指针变量,具有指针传递的...

  • golang 切片小结

    golang slice

  • golang中的slice

    上文讲解了数组这篇文章主要讲解Slice(切片)。Slice代表变长的序列,其里面的每个元素都有相同的类型。Sli...

  • golang中的slice

    上面这段代码神奇的地方就是 注释的部分。 其原因可以参考这篇文章 https://tiancaiamao.gitb...

网友评论

      本文标题:golang通道中传递slice数据的入坑经验

      本文链接:https://www.haomeiwen.com/subject/ymachxtx.html