Golang初学:高并发时写入数据到不同的map
go version go1.22.1 windows/amd64
Windows 11 + amd64
x86_64 x86_64 GNU/Linux
---
序章
多个 给 map 写入数据。
1、基本的map:make(map[any]any)
失败。
2、sync.Map
成功。
测试场景:
1K 个 goroutines 给同一个 map 各自写入 1W 数据,总1KW数据。
测试#1:普通map
代码:ben发布于博客园
// 多个 goroutines 写入 多个数据
// 百万+
// 失败
func testMap2() {
map0 := make(map[any]any)
fmt.Println("len#1: ", len(map0))
const num1 = 1_000
const num2 = 10_000
for i := range [num1]int{} {
go func() {
for j := range [num2]int{} {
key := fmt.Sprintf("k%d#%d", i, j)
map0[key] = j // fatal error: concurrent map writes
}
fmt.Println("go end i=", i)
}()
}
fmt.Println("len#2: ", len(map0))
time.Sleep(5 * time.Second)
fmt.Println("len#3: ", len(map0)) // 等于 num1 * num2 ?
fmt.Println("end.")
}
测试结果:
执行失败,出现了“fatal error: concurrent map writes”错误。
测试#2:sync.Map
// 多个 goroutines 写入数据
// 每个写入多个
func testMapForRoutines() {
map0ptr := new(sync.Map)
prtln("len of map #1: ", LenOfSyncMap(map0ptr))
const num1 = 1_000
const num2 = 10_000
for i := range [num1]int{} {
go func() {
for j := range [num2]int{} {
key := fmt.Sprintf("r#%d#%d", i, j)
map0ptr.Store(key, j)
}
prtln("end#i", i)
}()
}
prtln("len of map #2: ", LenOfSyncMap(map0ptr))
// sleepSeconds(10) // 数据 1KW 时,时间不够
sleepSeconds(30)
prtln("len of map #3: ", LenOfSyncMap(map0ptr))
// OutputSyncMap(map0ptr)
sleepSeconds(5)
prtln("end.")
}
测试结果:ben发布于博客园
len of map #1: 0 ... len of map #3: 10000000 |
用到的函数:计算长度
// 计算 sync.Map 长度
func LenOfSyncMap(map0 *sync.Map) (len int64) {
map0.Range(func(key, value any) bool {
len++
return true
})
return
}
注意,这里的返回值 有名称——len,因此,return 后面没有内容。
ben发布于博客园
type sync.Map 简介
https://pkg.go.dev/sync@go1.22.3#Map
具体请看 文档。
描述:
Map is like a Go map[any]any but is safe for concurrent use by multiple goroutines without additional locking or coordination. Loads, stores, and deletes run in amortized constant time. |
END.
ben发布于博客园
本文链接:
https://www.cnblogs.com/luo630/p/18190211
ben发布于博客园
参考资料
1、
ben发布于博客园
ben发布于博客园