ijd8.COM

A simple blog for an old Ma Nong.

Golang 中两个基本数据 map、slice 并发安全使用方法

Permalink5

当多线程对这两种数据类型同时进行 操作时,如果不对其做线程安全处理,得到的结果往往不是所期望的,还有可能降低性能或抛出错误。

常用的简单方法是加锁:

Go: sync.Mutex
1
2
3
4
5
6
7
8
9
10
var lock = sync.Mutex{}


var myList = []int{}


lock.Lock() // 加锁
myList = append(myList, 1)
lock.Unlock() // 解锁

map 类型除了可以使用上面的方式,还可以使用系统自带的 sync.Map 类型来代替,只是对 map 的操作稍有点不同。

Go: sync.Map
1
2
3
4
5
6
7
8
var mp = &sync.Map{}

mp.Store("k", 1)
if v, ok := mp.Load("k"); ok {
    fmt.Println(v)
}

mp.Delete("k")

sync.Map 还有几个有用的方法:

Go: 其它方法
1
2
LoadAndDelete(k)
LoadOrStore(k, v)

可以使用 Range 来遍历删除所有键

Go: sync.Map Range
1
2
3
4
mp.Range(func(k, _ interface{}) bool {
    mp.Delete(k)
    return true
})

其实 map 清空所有键值,使用下面的方法更佳:

Go: map 清空
1
mp = &sync.Map{}

Comments

There are 5 Comments to "Golang 中两个基本数据 map、slice 并发安全使用方法"

1 简单猪 says:
回复

在使用 sync.Map 做网站全局缓存时发现一个问题:

当 Delete 一个键后,再读取其它的 key 时可能出现一些意外错误,而当删除全部的 key 则不会出现这样的情况。

2 简单猪 says:
回复

@简单猪 #1 估计是我的姿势不对😄

3 简单猪 says:
回复

@简单猪 #1 是初始化时的一个小细节引起的问题

Go: sync.Map 初始化
1
2
3
4
5
6
7
8
9
10
mp := &sync.Map{} // 初始化
func f(m *sync.Map, k, v string) {
    m.Store("k", "v")
}

f(mp, "k", "v") // 调用

mp2 := sync.Map{} // 初始化
f(&mp2, "k", "v") // 调用

在实际使用中发现,mp 会不可预期的出现问题,mp2 正常。

4 简单猪 says:
回复

@简单猪 #3 错觉!!问题依旧,最终还是弃用 sync.Map

5 简单猪 says:
回复

@简单猪 #4 使用 fastcache

Write a Comment

Submit Comment Login
Based on Golang + fastHTTP + sdb | go1.16.7 Processed in 1ms