MST
星途 面试题库

面试题:Go语言Context设计模式在并发场景中的应用

在一个复杂的并发场景中,多个goroutine需要协同工作并且可能存在资源竞争。请阐述如何使用Context设计模式来优雅地管理这些goroutine的生命周期,避免资源泄露。同时,假设其中一个goroutine执行任务需要连接数据库,在超时的情况下,如何确保数据库连接正确关闭?请给出具体实现思路和关键代码片段。
27.6万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

使用Context管理goroutine生命周期及避免资源泄露思路

  1. 创建Context:在主goroutine中创建一个顶层的Context,通常使用context.Background()作为根Context,然后基于它衍生出带有取消功能或超时功能的Context
  2. 传递Context:将这个Context传递给所有需要管理生命周期的goroutine。每个goroutine在执行任务时,要定期检查Context的取消信号。
  3. 取消操作:当需要结束这些goroutine时,调用取消函数(由context.WithCancelcontext.WithTimeout返回的取消函数),所有接收该Context的goroutine会收到取消信号,从而安全地退出。

确保数据库连接在超时时正确关闭思路

  1. 使用带超时的Context:在连接数据库的goroutine中,使用context.WithTimeout创建一个带超时的Context
  2. 连接数据库:使用这个带超时的Context来执行数据库连接操作。
  3. 检查超时:在连接操作过程中,定期检查Context的状态。如果超时,取消数据库连接操作,并关闭已建立的连接(如果有)。

关键代码片段

package main

import (
    "context"
    "fmt"
    "net/http"
    "time"
)

func connectDB(ctx context.Context) error {
    // 创建一个模拟的数据库连接
    // 这里使用time.Sleep模拟连接操作耗时
    select {
    case <-time.After(2 * time.Second):
        fmt.Println("Database connection established")
        return nil
    case <-ctx.Done():
        fmt.Println("Database connection timed out")
        // 这里假设已经有连接建立,进行关闭操作
        // 实际应用中需根据具体数据库连接库实现
        return ctx.Err()
    }
}

func worker(ctx context.Context) {
    err := connectDB(ctx)
    if err != nil {
        fmt.Printf("Worker failed: %v\n", err)
    }
}

func main() {
    // 创建一个带超时的Context
    ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
    defer cancel()

    // 启动goroutine
    go worker(ctx)

    // 主线程等待一段时间
    time.Sleep(3 * time.Second)
}

在上述代码中:

  • connectDB函数模拟连接数据库操作,使用select语句监听time.Afterctx.Done()信号,以处理超时情况。
  • worker函数调用connectDB,并处理连接过程中的错误。
  • main函数创建一个带1秒超时的Context,启动worker goroutine,主线程等待3秒以观察结果。