• gmap
    • 使用示例
      • 示例1,基本使用
      • 示例2,有序遍历
    • 并发安全
    • 性能测试
      • 并发安全
      • 非并发安全
      • 不同类型map性能
      • gmap与sync.Map性能比较

    gmap

    支持可选并发安全特性的map容器,最常用的并发安全数据结构。

    该模块包含多个数据结构的map容器:Map/HashMapTreeMapListMap

    类型 数据结构 平均复杂度 支持排序 有序遍历 说明
    Map/HashMap 哈希表 O(1) 高性能读写操作,内存占用较高,随机遍历
    ListMap 哈希表+双向链表 O(2) 支持按照写入顺序遍历,内存占用较高
    TreeMap 红黑树 O(log N) 内存占用紧凑,支持键名排序及有序遍历

    其中MapHashMap的别名,为方便开发调用,gmap模块支持多种以哈希表为基础数据结构的常见类型map定义:IntIntMapIntStrMapIntAnyMapStrIntMapStrStrMapStrAnyMap

    参考链接:https://en.wikipedia.org/wiki/Hash_table

    使用场景

    任何map/哈希表/关联数组使用场景。

    使用方式

    1. import "github.com/gogf/gf/g/container/gmap"

    接口文档

    https://godoc.org/github.com/gogf/gf/g/container/gmap

    使用示例

    示例1,基本使用

    1. package main
    2. import (
    3. "fmt"
    4. "github.com/gogf/gf/g/container/gmap"
    5. )
    6. func main() {
    7. // 创建一个默认的gmap对象,
    8. // 默认情况下该gmap对象支持并发安全特性,
    9. // 初始化时可以给定true参数关闭并发安全特性,当做一个普通的map使用。
    10. m := gmap.New()
    11. // 设置键值对
    12. for i := 0; i < 10; i++ {
    13. m.Set(i, i)
    14. }
    15. // 查询大小
    16. fmt.Println(m.Size())
    17. // 批量设置键值对(不同的数据类型对象参数不同)
    18. m.Sets(map[interface{}]interface{}{
    19. 10 : 10,
    20. 11 : 11,
    21. })
    22. fmt.Println(m.Size())
    23. // 查询是否存在
    24. fmt.Println(m.Contains(1))
    25. // 查询键值
    26. fmt.Println(m.Get(1))
    27. // 删除数据项
    28. m.Remove(9)
    29. fmt.Println(m.Size())
    30. // 批量删除
    31. m.Removes([]interface{}{10, 11})
    32. fmt.Println(m.Size())
    33. // 当前键名列表(随机排序)
    34. fmt.Println(m.Keys())
    35. // 当前键值列表(随机排序)
    36. fmt.Println(m.Values())
    37. // 查询键名,当键值不存在时,写入给定的默认值
    38. fmt.Println(m.GetOrSet(100, 100))
    39. // 删除键值对,并返回对应的键值
    40. fmt.Println(m.Remove(100))
    41. // 遍历map
    42. m.Iterator(func(k interface{}, v interface{}) bool {
    43. fmt.Printf("%v:%v ", k, v)
    44. return true
    45. })
    46. // 自定义写锁操作
    47. m.LockFunc(func(m map[interface{}]interface{}) {
    48. m[99] = 99
    49. })
    50. // 自定义读锁操作
    51. m.RLockFunc(func(m map[interface{}]interface{}) {
    52. fmt.Println(m[99])
    53. })
    54. // 清空map
    55. m.Clear()
    56. // 判断map是否为空
    57. fmt.Println(m.IsEmpty())
    58. }

    执行后,输出结果为:

    1. 10
    2. 12
    3. true
    4. 1
    5. 11
    6. 9
    7. [0 1 2 4 6 7 3 5 8]
    8. [3 5 8 0 1 2 4 6 7]
    9. 100
    10. 100
    11. 3:3 5:5 8:8 7:7 0:0 1:1 2:2 4:4 6:6 99
    12. true

    示例2,有序遍历

    我们来看一下三种不同类型map的有序性遍历示例。

    1. package main
    2. import (
    3. "fmt"
    4. "github.com/gogf/gf/g"
    5. "github.com/gogf/gf/g/container/gmap"
    6. "github.com/gogf/gf/g/util/gutil"
    7. )
    8. func main() {
    9. array := g.Slice{2, 3, 1, 5, 4, 6, 8, 7, 9}
    10. hashMap := gmap.New(true)
    11. listMap := gmap.NewListMap(true)
    12. treeMap := gmap.NewTreeMap(gutil.ComparatorInt, true)
    13. for _, v := range array {
    14. hashMap.Set(v, v)
    15. }
    16. for _, v := range array {
    17. listMap.Set(v, v)
    18. }
    19. for _, v := range array {
    20. treeMap.Set(v, v)
    21. }
    22. fmt.Println("HashMap Keys:", hashMap.Keys())
    23. fmt.Println("HashMap Values:", hashMap.Values())
    24. fmt.Println("ListMap Keys:", listMap.Keys())
    25. fmt.Println("ListMap Values:", listMap.Values())
    26. fmt.Println("TreeMap Keys:", treeMap.Keys())
    27. fmt.Println("TreeMap Values:", treeMap.Values())
    28. }

    执行后,输出结果为:

    1. HashMap Keys: [4 6 8 7 9 2 3 1 5]
    2. HashMap Values: [6 8 4 3 1 5 7 9 2]
    3. ListMap Keys: [2 3 1 5 4 6 8 7 9]
    4. ListMap Values: [2 3 1 5 4 6 8 7 9]
    5. TreeMap Keys: [1 2 3 4 5 6 7 8 9]
    6. TreeMap Values: [1 2 3 4 5 6 7 8 9]

    并发安全

    gmap支持并发安全选项开关,在默认情况下是并发安全的,但是在某些对性能要求比较高的场景下,用户可以选择主动关闭gmap的并发安全特性(传递初始化开关参数unsafe值为true, 必须在初始化时设定,不能运行时动态设定),性能会得到一定提升,如:

    1. m := gmap.New(true)

    不仅仅是gmap模块,gf框架的其他并发安全数据结构也支持并发安全特性开关,来提升性能或者简化原本复杂的数据结构操作。

    性能测试

    并发安全

    https://github.com/gogf/gf/blob/master/g/container/gmap/gmap_z_bench_safe_test.go

    1. goos: darwin
    2. goarch: amd64
    3. Benchmark_IntIntMap_Set-4 10000000 202 ns/op 15 B/op 0 allocs/op
    4. Benchmark_IntAnyMap_Set-4 10000000 262 ns/op 29 B/op 1 allocs/op
    5. Benchmark_IntStrMap_Set-4 10000000 241 ns/op 22 B/op 0 allocs/op
    6. Benchmark_AnyAnyMap_Set-4 5000000 359 ns/op 40 B/op 2 allocs/op
    7. Benchmark_StrIntMap_Set-4 5000000 305 ns/op 26 B/op 1 allocs/op
    8. Benchmark_StrAnyMap_Set-4 5000000 354 ns/op 40 B/op 2 allocs/op
    9. Benchmark_StrStrMap_Set-4 5000000 338 ns/op 32 B/op 1 allocs/op
    10. Benchmark_IntIntMap_Get-4 20000000 86.6 ns/op 0 B/op 0 allocs/op
    11. Benchmark_IntAnyMap_Get-4 30000000 69.7 ns/op 0 B/op 0 allocs/op
    12. Benchmark_IntStrMap_Get-4 30000000 69.6 ns/op 0 B/op 0 allocs/op
    13. Benchmark_AnyAnyMap_Get-4 20000000 74.4 ns/op 0 B/op 0 allocs/op
    14. Benchmark_StrIntMap_Get-4 20000000 116 ns/op 7 B/op 0 allocs/op
    15. Benchmark_StrAnyMap_Get-4 20000000 92.3 ns/op 7 B/op 0 allocs/op
    16. Benchmark_StrStrMap_Get-4 20000000 91.9 ns/op 7 B/op 0 allocs/op

    非并发安全

    https://github.com/gogf/gf/blob/master/g/container/gmap/gmap_z_bench_unsafe_test.go

    1. goos: darwin
    2. goarch: amd64
    3. Benchmark_Unsafe_IntIntMap_Set-4 10000000 318 ns/op 62 B/op 0 allocs/op
    4. Benchmark_Unsafe_IntAnyMap_Set-4 5000000 282 ns/op 57 B/op 1 allocs/op
    5. Benchmark_Unsafe_IntStrMap_Set-4 5000000 332 ns/op 82 B/op 1 allocs/op
    6. Benchmark_Unsafe_AnyAnyMap_Set-4 3000000 471 ns/op 73 B/op 2 allocs/op
    7. Benchmark_Unsafe_StrIntMap_Set-4 5000000 429 ns/op 82 B/op 1 allocs/op
    8. Benchmark_Unsafe_StrAnyMap_Set-4 3000000 424 ns/op 73 B/op 2 allocs/op
    9. Benchmark_Unsafe_StrStrMap_Set-4 2000000 515 ns/op 96 B/op 2 allocs/op
    10. Benchmark_Unsafe_IntIntMap_Get-4 10000000 133 ns/op 0 B/op 0 allocs/op
    11. Benchmark_Unsafe_IntAnyMap_Get-4 20000000 134 ns/op 0 B/op 0 allocs/op
    12. Benchmark_Unsafe_IntStrMap_Get-4 10000000 126 ns/op 0 B/op 0 allocs/op
    13. Benchmark_Unsafe_AnyAnyMap_Get-4 10000000 166 ns/op 0 B/op 0 allocs/op
    14. Benchmark_Unsafe_StrIntMap_Get-4 5000000 246 ns/op 7 B/op 0 allocs/op
    15. Benchmark_Unsafe_StrAnyMap_Get-4 10000000 238 ns/op 7 B/op 0 allocs/op
    16. Benchmark_Unsafe_StrStrMap_Get-4 5000000 229 ns/op 7 B/op 0 allocs/op

    不同类型map性能

    https://github.com/gogf/gf/blob/master/g/container/gmap/gmap_z_bench_maps_test.go

    1. goos: darwin
    2. goarch: amd64
    3. Benchmark_HashMap_Set-4 5000000 349 ns/op 40 B/op 2 allocs/op
    4. Benchmark_ListMap_Set-4 3000000 455 ns/op 87 B/op 3 allocs/op
    5. Benchmark_TreeMap_Set-4 3000000 481 ns/op 28 B/op 2 allocs/op
    6. Benchmark_HashMap_Get-4 30000000 67.8 ns/op 0 B/op 0 allocs/op
    7. Benchmark_ListMap_Get-4 20000000 74.5 ns/op 0 B/op 0 allocs/op
    8. Benchmark_TreeMap_Get-4 20000000 189 ns/op 8 B/op 1 allocs/op

    gmap与sync.Map性能比较

    go语言从1.9版本开始引入了并发安全的sync.Map,但gmap比较于标准库的sync.Map性能更加优异,并且功能更加丰富。

    我们来看看基准测试对比结果:https://github.com/gogf/gf/blob/master/g/container/gmap/gmap_z_bench_syncmap_test.go

    1. goos: darwin
    2. goarch: amd64
    3. Benchmark_GMapSet-4 10000000 209 ns/op 15 B/op 0 allocs/op
    4. Benchmark_SyncMapSet-4 3000000 451 ns/op 67 B/op 3 allocs/op
    5. Benchmark_GMapGet-4 30000000 66.4 ns/op 0 B/op 0 allocs/op
    6. Benchmark_SyncMapGet-4 30000000 36.0 ns/op 0 B/op 0 allocs/op
    7. Benchmark_GMapRemove-4 10000000 207 ns/op 0 B/op 0 allocs/op
    8. Benchmark_SyncMapRmove-4 30000000 42.4 ns/op 0 B/op 0 allocs/op