MST

星途 面试题库

面试题:Go匿名函数并发应用中的资源竞争及优化

给定如下代码片段: ```go package main import ( "fmt" ) var count int func main() { for i := 0; i < 1000; i++ { go func() { count++ }() } fmt.Println(count) } ``` 这段代码用于在并发环境下对`count`进行累加操作,但运行结果往往不是1000。请分析原因,指出这是什么问题,并使用匿名函数和合适的同步机制对代码进行修改,确保`count`最终能够正确累加到1000 。
10.7万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

原因分析

  1. 竞态条件问题:这段代码中多个goroutine同时对count进行读写操作,由于没有同步机制,会导致竞态条件。在多个goroutine并发执行count++时,count++并非原子操作,它通常分为读取count的值、对值加1、再将结果写回count三个步骤。当多个goroutine同时执行这三个步骤时,可能会出现一个goroutine读取count的值后,另一个goroutine也读取了相同的值,然后两个goroutine分别加1并写回,这样就会丢失一次累加,导致最终结果小于1000。

修改代码

package main

import (
    "fmt"
    "sync"
)

var count int
var wg sync.WaitGroup

func main() {
    for i := 0; i < 1000; i++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            var mu sync.Mutex
            mu.Lock()
            count++
            mu.Unlock()
        }()
    }
    wg.Wait()
    fmt.Println(count)
}

在上述修改后的代码中:

  1. sync.WaitGroup:用于等待所有goroutine完成。在启动每个goroutine前调用wg.Add(1)增加等待组计数器,在goroutine结束时调用wg.Done()减少计数器。最后通过wg.Wait()阻塞主线程,直到所有goroutine执行完毕。
  2. sync.Mutex:用于同步对count的访问。在对count进行累加操作前,通过mu.Lock()加锁,操作完成后通过mu.Unlock()解锁,确保同一时间只有一个goroutine能够对count进行读写操作,避免竞态条件。