zoukankan      html  css  js  c++  java
  • golang slice使用不慎导致的问题

    原文链接 : http://www.bugclosed.com/post/16

    背景

    go语言中切片slice是方便且好用的强大数据结构,但是使用的时候需要注意,不然容易出问题,最近因为遇到了一个slice的使用问题,比较典型。
    有一个功能需求,用户需要获取1-20的不重复随机序列。

    逻辑实现

    由于是需要固定的1-20共20个不同数字,所以直接定义好了唯一序列如下:

    var(
    	originalNumbers = []uint32{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,13,14,15,16, 17, 18, 19, 20}
    )
    

    因为每个用户获取的数据的序列都需要随机打乱,实现的逻辑如下:

    
    func shuffle(list []uint32) []uint32 {
    	n := len(list)
    
    	for i := n - 1; i > 0; i-- {
    		j := dist.Int63n(int64(i + 1))
    		list[i], list[j] = list[j], list[i]
    	}
    
    	return list
    }
    
    func getOriginalNumbers() []uint32{
    	return originalNumbers
    }
    
    func GetRandomNumbers(cardType int) []uint32 {
    	return shuffle(getOriginalNumbers())
    }
    
    

    问题暴露

    通过仔细分析,从以上的逻辑其实是可以发现问题的,只是写代码的时候疏忽导致没有主要到潜在问题。运行的时候发现逻辑不正确,偶尔有用户得到的序列是有重复的数字。

    从原始数据的初始化来看,数字是1-20初始化到slice里面的,绝对不会出现重复。仔细看了GetRandoNumbers和shuffle打乱逻辑是存在并发访问问题的。

    首先originalNumbers是一个slice,参数传递slice时仅仅是传递的切片的指针,并非复制一份切片。所以在并发的情况下,每个用户的GetRandomNumbers都会获取到同一个slice地址。而shuffle函数会对得到切片数据进行写操作(数据打乱),当出现并发写问题的时候,数据发生错乱就不足为奇了。

    问题解决

    这个问题本质就是并发写问题,只需要将数据分离即可解决问题。

    func getOriginalNumbers() []uint32{
    	tmp := make([]uint32, len(originalNumbers))
    	copy(tmp, shortDeck)
    	return tmp
    }
    

    总结

    这是一个很典型的slice误用问题,slice是一个数据结构,他会指向底层真正的内存数据块,可以认为slice传递的是内存的指针。

  • 相关阅读:
    洛谷 P1226 【模板】快速幂||取余运算 题解
    洛谷 P2678 跳石头 题解
    洛谷 P2615 神奇的幻方 题解
    洛谷 P1083 借教室 题解
    洛谷 P1076 寻宝 题解
    洛谷 UVA10298 Power Strings 题解
    洛谷 P3375 【模板】KMP字符串匹配 题解
    Kafka Shell基本命令
    Mybatis与Hibernate的详细对比
    MyBatis简介
  • 原文地址:https://www.cnblogs.com/bugmaking/p/9083345.html
Copyright © 2011-2022 走看看