Golang中运行Slices时遇到的问题如何解决

Golang中运行Slices时遇到的问题如何解决 Screenshot 2022-01-30 at 3.43.07 PM

我无法排查这个错误?

欢迎并需要任何帮助。

2 回复

你好 @zaidzac95,

booking 是一个局部变量,而函数并没有返回它。因此它会被丢弃,所有追加的值都会丢失。

更多关于Golang中运行Slices时遇到的问题如何解决的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


这个错误是因为在并发环境下同时读写同一个切片导致的。切片在Go中不是并发安全的数据结构,当多个goroutine同时修改同一个切片时,会触发数据竞争检测。

错误信息显示:

  • concurrent slice writes:并发切片写入
  • fatal error: concurrent map writes:并发map写入(如果代码中还有map操作)

解决方案:使用互斥锁保护切片操作

package main

import (
    "fmt"
    "sync"
)

type SafeSlice struct {
    mu    sync.RWMutex
    items []int
}

func (s *SafeSlice) Append(item int) {
    s.mu.Lock()
    defer s.mu.Unlock()
    s.items = append(s.items, item)
}

func (s *SafeSlice) Get(index int) int {
    s.mu.RLock()
    defer s.mu.RUnlock()
    return s.items[index]
}

func main() {
    var wg sync.WaitGroup
    safeSlice := &SafeSlice{}

    // 启动多个goroutine并发写入
    for i := 0; i < 10; i++ {
        wg.Add(1)
        go func(val int) {
            defer wg.Done()
            safeSlice.Append(val)
        }(i)
    }

    wg.Wait()
    fmt.Println("Slice length:", len(safeSlice.items))
}

如果还需要并发安全的map,使用sync.Map:

package main

import (
    "fmt"
    "sync"
)

func main() {
    var wg sync.WaitGroup
    var m sync.Map

    // 并发写入map
    for i := 0; i < 10; i++ {
        wg.Add(1)
        go func(key int) {
            defer wg.Done()
            m.Store(key, fmt.Sprintf("value%d", key))
        }(i)
    }

    wg.Wait()

    // 读取map
    m.Range(func(key, value interface{}) bool {
        fmt.Printf("Key: %v, Value: %v\n", key, value)
        return true
    })
}

如果只需要简单的切片保护,可以直接使用sync.Mutex:

package main

import (
    "fmt"
    "sync"
)

func main() {
    var mu sync.Mutex
    var slice []int
    var wg sync.WaitGroup

    for i := 0; i < 10; i++ {
        wg.Add(1)
        go func(val int) {
            defer wg.Done()
            
            mu.Lock()
            slice = append(slice, val)
            mu.Unlock()
        }(i)
    }

    wg.Wait()
    fmt.Println("Final slice:", slice)
}

选择哪种方案取决于具体需求:

  1. 如果只有切片操作,使用sync.Mutex或封装成结构体
  2. 如果同时有map操作,使用sync.Map替代普通map
  3. 如果读写比例高,考虑使用sync.RWMutex提高读取性能
回到顶部