Go语言之sync.map

Admin 2022-05-23 16:59:52 GoLang

我们经常会碰到并发读写 map 而造成 panic 的情况,因为在并发读写的情况下,map 里的数据会被混乱(只读是线程安全的,同时读写是线程不安全的),对 map 并发读写时需要加锁,但这样性能并不高,Go语言在 1.9 版本中提供了一种效率较高的并发安全的 sync.Map,sync.Map 和 map 不同,不是以语言原生形态提供,而是在 sync 包下的特殊结构。

sync.Map 特性:

  1. 无须初始化,直接声明即可。

  2. 对键值对的类型没有限制,同一个sync.map中可存储多种类型的键值。

  3. sync.Map 不能使用 map 的方式进行取值和设置等操作,而是使用 sync.Map 的方法进行调用,Store 表示存储,Load 表示获取,Delete 表示删除。

  4. 使用 Range 配合一个回调函数进行遍历操作,通过回调函数返回内部遍历出来的值,Range 参数中回调函数的返回值在需要继续迭代遍历时,返回 true,终止迭代遍历时,返回 false。

sync.Map 优点:

  1. 是线程安全的,读取,插入,删除也都保持着常数级的时间复杂度。

  2. 零值是有效的,并且零值是一个空的 map。在第一次使用之后,不允许被拷贝。

  3. 通过读写分离,降低锁时间来提高效率,适用于读多写少的场景。

package main

import (
    "sync"
    "fmt"
)

func main() {
    var s sync.Map

    // 将键值对保存到sync.Map
    s.Store("k", "1")
    s.Store(1, 100)

    // 键值不存在则创建
    s.LoadOrStore("a", "2")

    // 从sync.Map中根据键取值
    fmt.Println(s.Load("k"))

    // 根据键删除对应的键值对
    s.Delete("k")

    // 遍历所有sync.Map中的键值对
    s.Range(func(k, v interface{}) bool {
        fmt.Println("iterate:", k, v)
        return true
    })
}

sync.Map 没有提供获取 map 数量的方法,替代方法是在获取 sync.Map 时遍历自行计算数量,sync.Map 为了保证并发安全有一些性能损失,因此在非并发情况下,使用 map 相比使用 sync.Map 会有更好的性能。

相关文章
最新推荐