MST

星途 面试题库

面试题:Go Context在并发请求中的资源管理

假设你正在开发一个微服务,这个微服务需要同时发起多个并发的HTTP请求去不同的后端服务获取数据,然后将这些数据整合返回。在这个过程中,如何使用Context进行请求的取消控制以及资源的合理管理,避免出现资源泄漏等问题,请用代码示例说明。
26.8万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

以下以Go语言为例:

package main

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

// 模拟从后端服务获取数据的函数
func fetchData(ctx context.Context, url string) (string, error) {
    req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
    if err != nil {
        return "", err
    }

    client := &http.Client{}
    resp, err := client.Do(req)
    if err != nil {
        return "", err
    }
    defer resp.Body.Close()

    // 这里简单返回URL,实际应该读取响应体
    return url, nil
}

func main() {
    // 创建一个带有取消功能的上下文
    ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
    defer cancel()

    urls := []string{
        "http://example.com/api1",
        "http://example.com/api2",
        "http://example.com/api3",
    }

    var results []string
    var errs []error

    var semaphore = make(chan struct{}, 3) // 限制并发数

    for _, url := range urls {
        semaphore <- struct{}{}
        go func(u string) {
            defer func() { <-semaphore }()
            data, err := fetchData(ctx, u)
            if err != nil {
                errs = append(errs, err)
            } else {
                results = append(results, data)
            }
        }(url)
    }

    // 等待所有请求完成
    for i := 0; i < len(urls); i++ {
        semaphore <- struct{}{}
    }
    for i := 0; i < len(urls); i++ {
        <-semaphore
    }

    if len(errs) > 0 {
        fmt.Println("Errors:", errs)
    } else {
        fmt.Println("Results:", results)
    }
}
  1. 上下文创建ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) 创建了一个带有超时(2秒)的上下文,defer cancel() 确保在函数结束时取消上下文,释放相关资源。
  2. 请求取消控制http.NewRequestWithContext(ctx, http.MethodGet, url, nil) 将上下文附加到HTTP请求中,如果上下文被取消(例如超时),HTTP请求也会被取消。
  3. 资源管理
    • 使用 defer resp.Body.Close() 关闭HTTP响应的Body,避免资源泄漏。
    • 使用信号量 semaphore 控制并发数,避免同时发起过多请求导致资源耗尽。