MST

星途 面试题库

面试题:Go中context的超时控制与资源释放

假设你正在编写一个涉及多个并发任务的Go程序,这些任务需要共享一个数据库连接资源。使用context来实现当整体操作超时时,不仅要取消所有并发任务,还要确保数据库连接被正确关闭,避免资源泄漏。请描述具体的实现思路和关键代码片段。
42.4万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

实现思路

  1. 创建一个带有超时的context.Context
  2. 在启动每个并发任务时,将context.Context传递进去。
  3. 在每个任务内部,通过context.Context监听取消信号,一旦接收到取消信号,立即停止任务。
  4. 确保在程序结束时,正确关闭数据库连接。

关键代码片段

package main

import (
    "context"
    "database/sql"
    "fmt"
    "net/http"
    "time"

    _ "github.com/go-sql-driver/mysql"
)

func main() {
    // 假设这里已经正确初始化了数据库连接
    db, err := sql.Open("mysql", "user:password@tcp(127.0.0.1:3306)/test")
    if err != nil {
        panic(err)
    }
    defer db.Close()

    // 创建带有超时的context
    ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
    defer cancel()

    var numTasks = 3
    var taskDone = make(chan struct{}, numTasks)

    for i := 0; i < numTasks; i++ {
        go func(ctx context.Context, taskID int) {
            defer func() { taskDone <- struct{}{} }()
            select {
            case <-ctx.Done():
                fmt.Printf("Task %d cancelled due to context cancellation\n", taskID)
                return
            default:
                // 模拟数据库操作
                _, err := db.ExecContext(ctx, "SELECT 1")
                if err != nil {
                    if ctx.Err() == context.Canceled || ctx.Err() == context.DeadlineExceeded {
                        fmt.Printf("Task %d cancelled due to context: %v\n", taskID, err)
                    } else {
                        fmt.Printf("Task %d database operation error: %v\n", taskID, err)
                    }
                    return
                }
                fmt.Printf("Task %d completed successfully\n", taskID)
            }
        }(ctx, i)
    }

    for i := 0; i < numTasks; i++ {
        <-taskDone
    }
    close(taskDone)
}
  1. 创建数据库连接:使用sql.Open打开数据库连接,并通过defer db.Close()确保程序结束时关闭连接。
  2. 创建带有超时的context:使用context.WithTimeout创建一个带有5秒超时的context.Context,同时获取取消函数cancel
  3. 并发任务:启动多个并发任务,每个任务接收context.Context。在任务内部,通过select语句监听ctx.Done()信号。如果接收到取消信号,任务立即停止。这里模拟了一个数据库操作db.ExecContext,如果操作过程中context.Context取消,数据库操作也会被取消。
  4. 等待任务完成:使用一个带缓冲的通道taskDone来等待所有任务完成。