MST

星途 面试题库

面试题:Go闭包在并发场景下的问题与解决

假设你有一个函数,它返回一个闭包,并且这个闭包会在多个goroutine中被调用,闭包会修改一个共享变量。描述可能出现的问题,并给出至少一种使用Go语言特性(如互斥锁、通道等)来解决这些问题的方法,并编写相应代码。
41.0万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

可能出现的问题

当闭包在多个 goroutine 中调用并修改共享变量时,会出现竞态条件(race condition)。多个 goroutine 同时访问和修改共享变量,可能导致数据不一致、结果不可预测等问题。

解决方法 - 使用互斥锁(Mutex)

通过互斥锁可以保证同一时间只有一个 goroutine 能够访问共享变量,从而避免竞态条件。

package main

import (
    "fmt"
    "sync"
)

func main() {
    counter := NewCounter()

    var wg sync.WaitGroup
    for i := 0; i < 10; i++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            counter.Increment()
        }()
    }

    wg.Wait()
    fmt.Println("Final count:", counter.Get())
}

func NewCounter() *Counter {
    return &Counter{}
}

type Counter struct {
    count int
    mu    sync.Mutex
}

func (c *Counter) Increment() {
    c.mu.Lock()
    c.count++
    c.mu.Unlock()
}

func (c *Counter) Get() int {
    c.mu.Lock()
    defer c.mu.Unlock()
    return c.count
}

解决方法 - 使用通道(Channel)

可以通过通道来顺序传递修改操作,从而避免竞态条件。

package main

import (
    "fmt"
    "sync"
)

func main() {
    counter := NewCounter()

    var wg sync.WaitGroup
    for i := 0; i < 10; i++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            counter.Increment()
        }()
    }

    go func() {
        wg.Wait()
        close(counter.ops)
    }()

    for result := range counter.results {
        fmt.Println("Final count:", result)
    }
}

func NewCounter() *Counter {
    c := &Counter{
        ops:    make(chan func()),
        results: make(chan int),
    }
    go c.run()
    return c
}

type Counter struct {
    count   int
    ops     chan func()
    results chan int
}

func (c *Counter) Increment() {
    c.ops <- func() {
        c.count++
    }
}

func (c *Counter) Get() int {
    var result int
    c.ops <- func() {
        result = c.count
    }
    return result
}

func (c *Counter) run() {
    for op := range c.ops {
        op()
    }
    close(c.results)
    c.results <- c.Get()
}