MST

星途 面试题库

面试题:Go通知退出机制下并发资源管理的优化策略

假设你正在开发一个高并发的Go应用,其中使用了通知退出机制。当收到退出通知时,如何高效地管理和释放所有正在运行的goroutine及其占用的资源(如数据库连接、文件句柄等),以避免性能瓶颈和资源泄漏,请详细说明实现思路和代码示例。
48.8万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

实现思路

  1. 使用context.Contextcontext.Context 用于在 goroutine 之间传递截止时间、取消信号等。在主程序中创建一个 context.Context,并将其传递给所有需要监控退出信号的 goroutine。当收到退出通知时,取消这个 context.Context,所有监听此 context.Context 的 goroutine 会收到取消信号并优雅退出。
  2. 资源管理:对于数据库连接、文件句柄等资源,在 goroutine 退出时及时关闭。可以在每个 goroutine 内部使用 defer 语句来确保资源在函数返回时关闭。

代码示例

package main

import (
    "context"
    "fmt"
    "os"
    "os/signal"
    "syscall"
    "time"
)

// 模拟一个使用资源的函数
func worker(ctx context.Context, id int) {
    // 模拟数据库连接
    fmt.Printf("Worker %d started\n", id)
    defer fmt.Printf("Worker %d stopped\n", id)

    for {
        select {
        case <-ctx.Done():
            // 收到取消信号,退出循环
            return
        default:
            // 模拟工作
            fmt.Printf("Worker %d is working\n", id)
            time.Sleep(1 * time.Second)
        }
    }
}

func main() {
    // 创建一个 context.Context 和取消函数
    ctx, cancel := context.WithCancel(context.Background())

    // 启动多个 goroutine
    numWorkers := 3
    for i := 0; i < numWorkers; i++ {
        go worker(ctx, i)
    }

    // 监听系统信号,如 SIGINT(Ctrl+C)和 SIGTERM
    sigs := make(chan os.Signal, 1)
    signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)

    go func() {
        sig := <-sigs
        fmt.Println()
        fmt.Println(sig)
        // 收到信号,取消 context.Context
        cancel()
    }()

    // 等待所有 goroutine 退出
    for {
        select {
        case <-ctx.Done():
            fmt.Println("All workers stopped, exiting main")
            return
        }
    }
}

代码说明

  1. worker 函数:模拟一个使用资源的 goroutine,在 ctx.Done() 通道接收到信号时退出,确保资源被释放。
  2. main 函数
    • 创建 context.Context 和取消函数 cancel
    • 启动多个 worker goroutine,并将 ctx 传递给它们。
    • 监听系统信号 SIGINTSIGTERM,收到信号时调用 cancel 函数取消 ctx
    • 主程序等待所有 worker goroutine 退出。

通过这种方式,可以高效地管理和释放所有正在运行的 goroutine 及其占用的资源,避免性能瓶颈和资源泄漏。