zoukankan      html  css  js  c++  java
  • 【转】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
    ", data)
    	data = data[:0]
    	// fmt.Printf("%p
    ", data)
    
    	data = append(data, []byte("aaa")...)
    	ch <- data
    
    	time.Sleep(time.Second * 5)
    }
    

    预测的运行结果:

    bbbbbbbbbb

    aaa

    但是肯定是有坑的

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

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

  • 相关阅读:
    1104.整除问题
    1101.表达式求值(难)
    1102.最小子面积矩阵
    1095.2的幂次方
    1094.String matching
    1093.WERTYU
    1096.日期差值
    1092.Fibonacci
    车站解题程序
    阶乘之和解题程序
  • 原文地址:https://www.cnblogs.com/oxspirt/p/11277544.html
Copyright © 2011-2022 走看看