MST

星途 面试题库

面试题:Go实参传递安全性与并发编程的关联

在Go的并发编程场景下,实参传递的安全性保障面临哪些新的挑战?如何通过合理的设计来避免因实参传递导致的并发安全问题?请举例说明。
45.9万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

面临的新挑战

  1. 数据竞争:多个goroutine可能同时访问和修改同一个实参,导致数据不一致。例如,一个goroutine读取实参的某个字段值,而另一个goroutine同时修改该字段,这就可能造成读取到的是一个中间状态的值。
  2. 未初始化或部分初始化:在并发场景下,实参可能在未完全初始化时就被传递给其他goroutine使用,导致程序出现错误行为。

避免并发安全问题的设计方法

  1. 互斥锁(Mutex):使用sync.Mutex来保护对实参的访问。在读取或修改实参前先获取锁,操作完成后释放锁。
package main

import (
    "fmt"
    "sync"
)

var mu sync.Mutex
var count int

func increment(wg *sync.WaitGroup) {
    mu.Lock()
    count++
    mu.Unlock()
    wg.Done()
}

func main() {
    var wg sync.WaitGroup
    for i := 0; i < 10; i++ {
        wg.Add(1)
        go increment(&wg)
    }
    wg.Wait()
    fmt.Println("Final count:", count)
}
  1. 读写锁(RWMutex):当对实参的操作读多写少的场景下,使用sync.RWMutex。读操作时可以多个goroutine同时进行,写操作时则需要独占锁。
package main

import (
    "fmt"
    "sync"
)

var rwmu sync.RWMutex
var data string

func readData(wg *sync.WaitGroup) {
    rwmu.RLock()
    fmt.Println("Read data:", data)
    rwmu.RUnlock()
    wg.Done()
}

func writeData(wg *sync.WaitGroup) {
    rwmu.Lock()
    data = "new data"
    rwmu.Unlock()
    wg.Done()
}

func main() {
    var wg sync.WaitGroup
    for i := 0; i < 5; i++ {
        wg.Add(1)
        go readData(&wg)
    }
    for i := 0; i < 2; i++ {
        wg.Add(1)
        go writeData(&wg)
    }
    wg.Wait()
}
  1. 通道(Channel):通过通道在goroutine之间传递数据,保证数据的顺序性和安全性。通道会对数据进行缓冲和同步,避免数据竞争。
package main

import (
    "fmt"
)

func sender(ch chan int) {
    for i := 0; i < 5; i++ {
        ch <- i
    }
    close(ch)
}

func receiver(ch chan int) {
    for num := range ch {
        fmt.Println("Received:", num)
    }
}

func main() {
    ch := make(chan int)
    go sender(ch)
    receiver(ch)
}