• golang 使用 make 创建 map 是否需要指定长度


    大家都知道可以使用make方法来创建map类型,对比创建 slice 类型,创建map是否也需要指定len和cap两个参数呢?

    如果map要容纳的数据比较多,其实是需要指定len属性的,我们可以从创建map的源码中了解到(本文都采用go1.18的源码):

    makemap
    通过源码注释我们可以了解到,hint 就是make创建map指定的第二个参数。那么,这个参数如何决定map内部实际存储的大小呢?

    通过 hint来计算 B 的值,B作为map结构体中的一个属性,用来间接标识容量的数量。map最多可以容纳 负载因子 乘以 2的B次幂的数据。当然,我们看看这个 for 循环退出的条件是什么?

    overLoadFactor
    下面是函数overLoadFactor的源码,结合外面的for 循环,通过不断的B++,最终计算结果大于 hint 就会退出循环。其中,bucketCnt 是一个值为8的常量,所以,我们make指定len 的时候,如果值小于8就别指定了。然后就是与运算符右边的表达式了。

    常量loadFactorNum和loadFactorDen的值分别为13和2,然后bucketShift(B)的左右就是返回2的B次幂。按照这个逻辑,如果hint是9的话,B等于1,当hint为14的时候,B等于2,以此类推。

    // overLoadFactor reports whether count items placed in 1<
    func overLoadFactor(count int, B uint8) bool {
    	return count > bucketCnt && uintptr(count) > loadFactorNum*(bucketShift(B)/loadFactorDen)
    }
    
    • 1
    • 2
    • 3
    • 4

    现在通过 hint 获取到了B值,也就是通过make方法的len参数计算到了B值,准确的说,B在map中用来标志 bucket 的个数。

    最终我们还是要回到申请bucket空间上面,申请的代码可查看函数 makeBucketArray。函数用来申请底层的数组结构,为了简单期间,我们忽略参数 dirtyalloc 的作用,直捣黄龙。

    makeBucketArraty
    这里假设参数 b 等于4,那么base等于2的4次幂,值为16。考虑到可能出来溢出,会考虑多加1个bucket,所以,nbuckets 现在等于 16 + 1 了。然后我们就可以计算并申请空间了。

    在这里插入图片描述

    计算申请所需空间的函数也可以了解一下,Go 将申请的空间预设成了不同规格的大小块,我们需要要在申请的空间能被这些块覆盖。大概就跟寄快递一样,快递的纸箱盒子都是预设好的,有不同规格的大小,我们要邮寄的东西必须选择最合适的那个纸箱

    在这里插入图片描述
    总结:

    如果map要存储的数据比较多,在make创建map的时候,非常有必要指定参数len

  • 相关阅读:
    JavaScript中函数的声明方式、作用域
    栈的概念及用法
    lottie 如何停留最后一帧
    JAVA-线程
    curl: (56) Recv failure: Connection reset by peer
    抖音集团基于 Apache Doris 的实时数据仓库实践
    【无标题】
    SaaS系统用户权限设计
    Java - 根据文件绝对路径,来删除文件
    信息获取技术复习
  • 原文地址:https://blog.csdn.net/f1520107395/article/details/128010980