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传递的是内存的指针。

  • 相关阅读:
    webpack : 无法加载文件 D: odejs ode_globalwebpack.ps1,因为在此系统上禁止运行脚本。
    TypeError: __WEBPACK_IMPORTED_MODULE_0_react___default.a.createContext is not a function报错处理
    React中import的用法
    antd-react-mobile(踩坑记录)
    [转][C#]BarCodeToHTML
    [转][C#]Environment 类
    [转][easyui]右键菜单
    [转][C#]Web.config 相关配置
    [转]模拟键盘输入
    python3 的 zip
  • 原文地址:https://www.cnblogs.com/bugmaking/p/9083345.html
Copyright © 2011-2022 走看看