MST

星途 面试题库

面试题:Go语言中context在并发操作下的资源管理

假设你正在开发一个Go程序,需要并发执行多个任务,这些任务共享一些资源(如数据库连接)。使用context来管理这些并发任务的生命周期,并确保在任务取消或超时后,能够正确释放共享资源。请详细描述实现思路,并给出核心代码片段。
11.5万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

实现思路

  1. 创建context:使用context.WithCancelcontext.WithTimeout创建一个上下文对象,用于控制并发任务的生命周期。context.WithCancel可以手动取消任务,context.WithTimeout则在指定时间后自动取消任务。
  2. 启动并发任务:在go协程中执行任务,每个任务接收创建的上下文对象作为参数。在任务执行过程中,定期检查上下文的取消信号,如通过ctx.Done()通道是否关闭来判断。
  3. 共享资源管理:将共享资源(如数据库连接)封装在一个结构体中,并提供获取和释放资源的方法。在任务开始时获取资源,在任务结束(无论正常结束还是因取消或超时结束)时释放资源。

核心代码片段

package main

import (
    "context"
    "fmt"
    "sync"
    "time"
)

// Resource 模拟共享资源
type Resource struct {
    // 这里可以是数据库连接等实际资源
    Data string
}

// ResourceManager 资源管理器
type ResourceManager struct {
    resources sync.Map
}

// GetResource 获取资源
func (rm *ResourceManager) GetResource(key string) *Resource {
    res, ok := rm.resources.Load(key)
    if ok {
        return res.(*Resource)
    }
    newRes := &Resource{Data: "new resource for " + key}
    rm.resources.Store(key, newRes)
    return newRes
}

// ReleaseResource 释放资源
func (rm *ResourceManager) ReleaseResource(key string) {
    rm.resources.Delete(key)
}

func task(ctx context.Context, key string, rm *ResourceManager) {
    res := rm.GetResource(key)
    defer rm.ReleaseResource(key)

    for {
        select {
        case <-ctx.Done():
            fmt.Printf("Task %s cancelled, releasing resource\n", key)
            return
        default:
            fmt.Printf("Task %s is working with resource: %v\n", key, res)
            time.Sleep(1 * time.Second)
        }
    }
}

func main() {
    ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
    defer cancel()

    var rm ResourceManager

    var wg sync.WaitGroup
    wg.Add(2)

    go func() {
        task(ctx, "task1", &rm)
        wg.Done()
    }()

    go func() {
        task(ctx, "task2", &rm)
        wg.Done()
    }()

    wg.Wait()
    fmt.Println("All tasks completed")
}

在上述代码中:

  1. Resource结构体模拟共享资源,ResourceManager结构体管理这些资源。
  2. task函数是具体的并发任务,接收上下文和资源管理器作为参数。任务中获取资源,通过ctx.Done()通道监听取消信号,在任务结束时释放资源。
  3. main函数中创建了一个带超时的上下文,启动两个并发任务,并等待它们完成。