MST

星途 面试题库

面试题:Go语言匿名函数作用域在复杂并发场景下的问题与优化

在一个高并发的Go程序中,多个匿名函数被用于处理不同的任务,且这些匿名函数需要共享和修改一些全局变量。由于匿名函数的作用域特性,程序出现了数据不一致和资源竞争的问题。请描述你将如何分析问题的根源,并提出全面的优化方案,包括但不限于使用合适的同步机制、优化作用域设计等。同时,给出优化后的代码示例。
29.4万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

问题根源分析

  1. 作用域问题:匿名函数在不同的goroutine中执行,虽然共享全局变量,但每个匿名函数有自己独立的执行上下文,可能会在不同时间点访问和修改全局变量,导致数据不一致。
  2. 资源竞争:多个goroutine同时读写全局变量,没有适当的同步机制,就会引发资源竞争问题。

优化方案

  1. 同步机制
    • 互斥锁(Mutex):使用sync.Mutex来保护对全局变量的读写操作。在访问和修改全局变量前加锁,操作完成后解锁。
    • 读写锁(RWMutex):如果读操作远多于写操作,可以使用sync.RWMutex。读操作时可以多个goroutine同时进行,写操作时则需要独占锁。
  2. 优化作用域设计
    • 封装全局变量:将全局变量封装在一个结构体中,并提供方法来操作这些变量,在方法内部使用同步机制。
    • 传递参数:尽量避免直接使用全局变量,而是将需要的数据作为参数传递给匿名函数,减少共享状态。

优化后的代码示例

package main

import (
    "fmt"
    "sync"
)

// 封装全局变量
type SharedData struct {
    value int
    mutex sync.Mutex
}

// 获取值的方法
func (sd *SharedData) Get() int {
    sd.mutex.Lock()
    defer sd.mutex.Unlock()
    return sd.value
}

// 设置值的方法
func (sd *SharedData) Set(v int) {
    sd.mutex.Lock()
    defer sd.mutex.Unlock()
    sd.value = v
}

func main() {
    var wg sync.WaitGroup
    sharedData := SharedData{}

    // 模拟多个任务
    for i := 0; i < 10; i++ {
        wg.Add(1)
        go func(id int) {
            defer wg.Done()
            // 操作共享数据
            sharedData.Set(id)
            fmt.Printf("Goroutine %d set value to %d\n", id, sharedData.Get())
        }(i)
    }

    wg.Wait()
}

在这个示例中,我们将全局变量封装在SharedData结构体中,并使用sync.Mutex来保护对value的读写操作。每个匿名函数通过调用SetGet方法来操作共享数据,从而避免了资源竞争和数据不一致的问题。