MST

星途 面试题库

面试题:Go语言recover与并发场景结合的深度应用

在一个高度并发的Go程序中,多个goroutine可能会因为资源竞争、数据不一致等问题发生panic。请阐述如何利用recover在这种复杂并发场景下进行有效的错误处理和恢复,保证程序的健壮性。例如,假设一个共享资源的读写操作在多个goroutine中并发进行,可能会导致数据损坏进而引发panic,设计一个机制使用recover捕获这些panic,并协调各个goroutine保证数据一致性,同时尽量减少性能损耗。要求详细描述设计思路、数据结构、同步机制以及核心代码实现。
19.4万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

设计思路

  1. 错误处理与恢复:利用Go语言的defer和recover机制,在每个可能发生panic的goroutine中使用defer语句注册一个函数,该函数使用recover捕获panic,从而防止程序崩溃。
  2. 数据一致性:通过互斥锁(sync.Mutex)来保护共享资源的读写操作,确保同一时间只有一个goroutine能够访问共享资源,避免数据竞争和损坏。
  3. 性能优化:尽量减少锁的使用范围,只在实际读写共享资源时加锁,减少不必要的性能损耗。同时,对于频繁读取的场景,可以考虑使用读写锁(sync.RWMutex)提高并发性能。

数据结构

  1. 共享资源:定义一个结构体来表示共享资源,例如:
type SharedResource struct {
    data int
    mu   sync.Mutex
}
  1. 错误处理与协调:可以使用一个通道(chan)来通知其他goroutine发生了panic并进行相应的处理。例如:
type PanicInfo struct {
    err  interface{}
    from string
}

var panicChan = make(chan PanicInfo)

同步机制

  1. 互斥锁:使用sync.MutexLockUnlock方法来保护共享资源的读写操作。
  2. 读写锁:对于读多写少的场景,可以使用sync.RWMutexRLockRUnlock(读操作)和LockUnlock(写操作)方法。

核心代码实现

package main

import (
    "fmt"
    "sync"
)

type SharedResource struct {
    data int
    mu   sync.Mutex
}

type PanicInfo struct {
    err  interface{}
    from string
}

var panicChan = make(chan PanicInfo)

func (sr *SharedResource) Read() int {
    sr.mu.Lock()
    defer sr.mu.Unlock()
    return sr.data
}

func (sr *SharedResource) Write(newData int) {
    sr.mu.Lock()
    defer sr.mu.Unlock()
    sr.data = newData
}

func worker(sr *SharedResource, id int) {
    defer func() {
        if r := recover(); r != nil {
            panicChan <- PanicInfo{
                err:  r,
                from: fmt.Sprintf("worker %d", id),
            }
        }
    }()
    // 模拟一些可能导致panic的操作
    for i := 0; i < 10; i++ {
        sr.Write(i)
        value := sr.Read()
        fmt.Printf("Worker %d read value: %d\n", id, value)
        if i == 5 {
            // 模拟一个可能导致panic的操作
            panic("Simulated panic")
        }
    }
}

func main() {
    var wg sync.WaitGroup
    sharedResource := &SharedResource{}

    for i := 0; i < 3; i++ {
        wg.Add(1)
        go func(id int) {
            defer wg.Done()
            worker(sharedResource, id)
        }(i)
    }

    go func() {
        for panicInfo := range panicChan {
            fmt.Printf("Panic caught from %s: %v\n", panicInfo.from, panicInfo.err)
            // 这里可以进行一些恢复操作,例如重置共享资源
        }
    }()

    wg.Wait()
    close(panicChan)
}

在上述代码中:

  1. SharedResource结构体包含共享数据data和一个互斥锁mu
  2. ReadWrite方法分别用于读取和写入共享资源,通过互斥锁保护数据一致性。
  3. worker函数模拟一个goroutine,在其中进行共享资源的读写操作,并使用defer和recover捕获可能发生的panic,将panic信息发送到panicChan
  4. main函数中,启动多个worker goroutine,并通过wg等待所有goroutine完成。同时,有一个goroutine从panicChan中接收panic信息并进行处理。