MST
星途 面试题库

面试题:Go语言defer与并发场景下的注意事项

在Go语言的并发编程场景中,使用defer会带来哪些潜在的问题或需要特别注意的地方?例如,在多个goroutine同时使用defer来操作共享资源时,可能会遇到什么问题,如何解决?请详细阐述,并给出相应的代码示例及分析。
44.5万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

潜在问题

  1. 资源竞争:当多个goroutine通过defer操作共享资源时,可能会出现资源竞争问题。例如多个goroutine同时对同一个文件进行写入操作,若没有适当的同步机制,数据可能会出现错乱。
  2. 内存泄漏:如果在defer函数中持有对一些资源的引用,而这些资源没有被正确释放,可能会导致内存泄漏。比如在defer函数中忘记关闭文件句柄。

多个goroutine中使用defer操作共享资源的问题及解决

在多个goroutine中使用defer操作共享资源,最常见的问题就是资源竞争。例如,多个goroutine可能会同时尝试对共享的map进行写入操作,这会导致数据不一致。

解决办法是使用Go语言提供的同步机制,如sync.Mutex(互斥锁)来保护共享资源。

代码示例

package main

import (
    "fmt"
    "sync"
)

var (
    sharedMap = make(map[string]int)
    mu        sync.Mutex
)

func updateMap(key string, value int) {
    mu.Lock()
    defer mu.Unlock()
    sharedMap[key] = value
}

func main() {
    var wg sync.WaitGroup
    for i := 0; i < 10; i++ {
        wg.Add(1)
        go func(id int) {
            defer wg.Done()
            key := fmt.Sprintf("key%d", id)
            updateMap(key, id)
        }(i)
    }
    wg.Wait()
    fmt.Println(sharedMap)
}

代码分析

  1. 共享资源与锁的定义:定义了一个共享的mapsharedMap)和一个互斥锁(mu)。
  2. 更新共享资源的函数updateMap函数使用mu.Lock()锁定互斥锁,在函数结束时通过defer mu.Unlock()解锁。这样就保证了在同一时间只有一个goroutine可以操作sharedMap
  3. 并发操作:在main函数中,启动10个goroutine并发调用updateMap函数。每个goroutine完成后调用wg.Done()通知等待组。
  4. 等待所有goroutine完成wg.Wait()等待所有goroutine完成,然后打印sharedMap,此时sharedMap中的数据是正确更新且不会出现数据竞争导致的不一致问题。