Go语言中的map使用及并发安全

首先,Go语言的map底层是哈希表,而C++map的底层是红黑树,C++unordered_map的底层才是哈希表。所以增删改查的时间复杂度都是O(1)。当我们使用的时候需要注意以下几点:

  1. map是引用类型,如果两个map同时指向一个底层,那么一个map的变动会影响到另一个map,这一点需要特殊注意。

  2. map的零值(Zero Value)是nil,对nil map进行任何添加元素的操作都会触发运行时错误(panic)。因此,使用必须先创建map,使用make函数,例如:

    func f(int n) {
        m := make([]map[int]int, n)
        for i := range m {
            m[i] = make(map[int]int) // m中的所有map在使用前必须初始化
        }
    }
    
  3. map的键可以是任何可以用==!=操作符比较的类型,比如字符串、整数、浮点数、复数和布尔类型等。但是,slice, map, function等类型不可以作为map的键。

  4. map在使用过程中不保证顺序遍历,每次遍历的结果可能会不同,这一点和C++unordered_map相似。

  5. map进行的所有操作,增删改都不是线程安全的,如果在一个goroutine中修改了map,同时在另一个goroutine中读取了map,可能会触发concurrent map read and map write的错误。

并发安全:

由上述的第五点可知,Go语言的map不是并发安全的。并发情况下,对于map的读写操作都需要加锁,或者会引起竞争条件甚至导致程序崩溃。为了在并发环境下使用map,我们可以使用sync包中的sync.RWMutex读写锁,或者使用sync.Map

比如,我们可以使用读写锁来保证多个goroutine都可以访问同一个map:

var m = make(map[string]int)
var mutex = &sync.RWMutex{}
// 基本使用流程与C++和Java中锁的流程类似
func write(key string, value int) {
    mutex.Lock()
    m[key] = value
    mutex.Unlock()
}

func read(key string) (int, bool) {
    mutex.Lock()
    defer mutex.RUnlock()
    value, ok := m[key]
    return value, ok
}

再比如,我们也可以使用sync.Map{}完成并发控制:

func f() {
	m := sync.Map{}

	list := []string{"A", "B", "C", "D"}

	wg := sync.WaitGroup{}
	// 添加协程,等待协程完成
	for i := 0; i < 20; i++ {
		// 启动20组协程
		wg.Add(1)
		// 添加协程数量,一次只启动一个
		go func() {
			defer wg.Done() // 协程结束之后 wg - 1
			for _, item := range list {
				// 存在则 + 1, 不存在则初始化为1
				value, ok := m.Load(item)
				if !ok {
					value, _ = m.LoadOrStore(item, 0)
				}
				val := value.(int) + 1
				m.Store(item, val)
			}
		}()
	}
	wg.Wait() // 等待所有协程完成
	m.Range(func(k, v any) bool {
		fmt.Println(k, v)
		return true
	})
	fmt.Println(m)
}

最后给大家推荐一个LinuxC/C++高级架构系统教程的学习资源与课程,可以帮助你有方向、更细致地学习C/C++后端开发,具体内容请见 https://xxetb.xetslk.com/s/1o04uB

相关推荐

  1. Go语言map使用并发安全

    2024-05-01 07:22:07       43 阅读
  2. Go 语言 Map

    2024-05-01 07:22:07       37 阅读
  3. Go 语言并发威力

    2024-05-01 07:22:07       60 阅读
  4. Go怎么实现map并发安全三种方式

    2024-05-01 07:22:07       30 阅读
  5. go 语言 map 相关知识

    2024-05-01 07:22:07       43 阅读
  6. Go语言map并发安全,互斥锁和读写锁谁更优?

    2024-05-01 07:22:07       25 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-05-01 07:22:07       98 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-05-01 07:22:07       106 阅读
  3. 在Django里面运行非项目文件

    2024-05-01 07:22:07       87 阅读
  4. Python语言-面向对象

    2024-05-01 07:22:07       96 阅读

热门阅读

  1. VUE2从入门到精通(一)

    2024-05-01 07:22:07       28 阅读
  2. 0115__i++循环与i--循环的执行效率

    2024-05-01 07:22:07       34 阅读
  3. HTML 表单标签

    2024-05-01 07:22:07       36 阅读
  4. 第二章:计算机系统基础知识之系统工程

    2024-05-01 07:22:07       26 阅读
  5. MongoDB聚合运算符:$strLenBytes

    2024-05-01 07:22:07       35 阅读
  6. RCE漏洞简单总结

    2024-05-01 07:22:07       31 阅读
  7. MongoDB聚合运算符:$strLenCP

    2024-05-01 07:22:07       33 阅读
  8. Scala 重难点总结

    2024-05-01 07:22:07       38 阅读
  9. link和@import的区别

    2024-05-01 07:22:07       31 阅读
  10. iOS cocoapods 升级

    2024-05-01 07:22:07       33 阅读
  11. scala基础学习--变量,标识符,类型和类型转换

    2024-05-01 07:22:07       42 阅读
  12. redis多用户管理

    2024-05-01 07:22:07       35 阅读
  13. Docker 快速入门

    2024-05-01 07:22:07       33 阅读