Golang中如何在goroutines中使用map
Golang中如何在goroutines中使用map 我正在尝试更多地理解竞态条件,因此编写了这个程序,它基本上只是递增映射中的一个值。
在goroutine中对映射进行并发访问应该使用某种同步机制,这就是为什么我在这里使用了互斥锁。
由于程序使用了WaitGroup和互斥锁进行同步,映射中的最终值应该是100,但我们得到的结果并非如此。
我是否遗漏了什么?
package main
import (
"fmt"
"sync"
)
var wg sync.WaitGroup
type mapData struct {
sync.RWMutex
data map[string]int
}
func (m *mapData) read(key string) int {
m.RLock()
defer m.RUnlock()
return m.data[key]
}
func (m *mapData) write(key string) {
m.Lock()
m.data[key]++
m.Unlock()
wg.Done()
}
func main() {
m := mapData{}
m.data = make(map[string]int)
for i := 1; i <= 100; i++ {
wg.Add(1)
go m.write("a")
}
fmt.Println(m.read("a"))
wg.Wait()
}
更多关于Golang中如何在goroutines中使用map的实战教程也可以访问 https://www.itying.com/category-94-b0.html
3 回复
最终的答案应该是100。
最终的答案是100。你只需要耐心地 Wait!
wg.Wait()
fmt.Println("final", m.read("a"))
package main
import (
"fmt"
"sync"
)
var wg sync.WaitGroup
type mapData struct {
sync.RWMutex
data map[string]int
}
func (m *mapData) read(key string) int {
m.RLock()
defer m.RUnlock()
return m.data[key]
}
func (m *mapData) write(key string) {
m.Lock()
m.data[key]++
m.Unlock()
wg.Done()
}
func main() {
m := mapData{}
m.data = make(map[string]int)
for i := 1; i <= 100; i++ {
wg.Add(1)
go m.write("a")
}
fmt.Println(m.read("a"))
wg.Wait()
fmt.Println("final", m.read("a"))
}
final 100
你的代码存在一个关键问题:fmt.Println(m.read("a")) 在 wg.Wait() 之前执行,这意味着主 goroutine 在等待所有写操作完成之前就尝试读取映射值。这会导致竞态条件,因为读取发生时写 goroutines 可能仍在执行。
以下是修正后的代码:
package main
import (
"fmt"
"sync"
)
var wg sync.WaitGroup
type mapData struct {
sync.RWMutex
data map[string]int
}
func (m *mapData) read(key string) int {
m.RLock()
defer m.RUnlock()
return m.data[key]
}
func (m *mapData) write(key string) {
m.Lock()
m.data[key]++
m.Unlock()
wg.Done()
}
func main() {
m := mapData{}
m.data = make(map[string]int)
for i := 1; i <= 100; i++ {
wg.Add(1)
go m.write("a")
}
wg.Wait() // 等待所有写操作完成
fmt.Println(m.read("a")) // 现在安全读取
}
输出:
100
另一个更简洁的版本,使用 sync.Map 处理并发映射访问:
package main
import (
"fmt"
"sync"
)
func main() {
var m sync.Map
var wg sync.WaitGroup
for i := 0; i < 100; i++ {
wg.Add(1)
go func() {
defer wg.Done()
val, _ := m.LoadOrStore("a", 0)
m.Store("a", val.(int)+1)
}()
}
wg.Wait()
val, _ := m.Load("a")
fmt.Println(val) // 100
}
sync.Map 提供了线程安全的 Load、Store、LoadOrStore 等方法,适用于键值对数量较多或键值对频繁更新的并发场景。


