MST
星途 面试题库

面试题:Go中Context在并发请求控制的应用

假设你正在开发一个微服务,该微服务需要同时调用多个下游服务获取数据并汇总。如果其中一个下游服务响应过慢,你如何使用Go的Context来控制请求,避免整个微服务的响应时间过长?请描述具体实现思路并给出简单代码示例。
20.1万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

实现思路

  1. 创建一个带有超时的 Context。这个 Context 会被传递到所有下游服务的调用中。
  2. 使用 Gogoroutine 并发调用各个下游服务。
  3. 每个 goroutine 都监听 Context 的取消信号。如果在下游服务响应之前 Context 被取消(超时),则该 goroutine 应停止操作并返回。
  4. 使用 sync.WaitGroup 来等待所有 goroutine 完成,或者在超时时提前结束等待。

代码示例

package main

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

// 模拟下游服务调用
func downstreamService(ctx context.Context, name string, duration time.Duration, resultChan chan string) {
    select {
    case <-time.After(duration):
        resultChan <- fmt.Sprintf("%s service completed", name)
    case <-ctx.Done():
        resultChan <- fmt.Sprintf("%s service cancelled", name)
    }
}

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

    var wg sync.WaitGroup
    resultChan := make(chan string, 3)

    // 启动多个goroutine调用下游服务
    services := []struct {
        name     string
        duration time.Duration
    }{
        {"Service1", 2 * time.Second},
        {"Service2", 4 * time.Second},
        {"Service3", 1 * time.Second},
    }

    for _, service := range services {
        wg.Add(1)
        go func(s struct {
            name     string
            duration time.Duration
        }) {
            defer wg.Done()
            downstreamService(ctx, s.name, s.duration, resultChan)
        }(service)
    }

    go func() {
        wg.Wait()
        close(resultChan)
    }()

    // 收集结果
    for result := range resultChan {
        fmt.Println(result)
    }
}

在上述代码中:

  1. downstreamService 函数模拟下游服务调用,它接收 Context、服务名称、模拟的响应时间以及结果通道。它会在 Context 取消或等待指定时间后向结果通道发送结果。
  2. main 函数中,创建了一个 3 秒超时的 Context
  3. 启动多个 goroutine 并发调用 downstreamService,每个 goroutine 对应一个下游服务。
  4. 使用 sync.WaitGroup 等待所有 goroutine 完成,并在所有 goroutine 完成后关闭结果通道。
  5. 最后通过遍历结果通道来获取每个下游服务的执行结果,若某个服务超时,Context 取消,对应的 goroutine 会收到取消信号并停止操作。