MST

星途 面试题库

面试题:Go语言中Context包在并发中的基础应用

请简述Go语言中Context包的作用,以及在一个简单的并发任务场景中(比如多个goroutine同时请求外部API,若其中一个失败则全部取消),如何使用Context包来实现任务的取消和超时控制?请给出简要代码示例。
36.5万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

Context包的作用

Context包主要用于在多个goroutine之间传递截止时间、取消信号和其他请求范围的值。它允许对一组相关的goroutine进行集中管理,实现任务取消、超时控制以及传递请求特定的数据。例如在Web服务中,当客户端断开连接时,可以通过Context通知所有相关的goroutine停止工作,避免资源浪费。

并发任务场景下使用Context实现任务取消和超时控制

下面是一个简单示例,模拟多个goroutine同时请求外部API,若其中一个失败则全部取消:

package main

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

// 模拟请求外部API
func mockAPI(ctx context.Context, id int) error {
    select {
    case <-time.After(2 * time.Second): // 模拟API请求时间
        fmt.Printf("goroutine %d success\n", id)
        return nil
    case <-ctx.Done():
        fmt.Printf("goroutine %d cancelled\n", id)
        return ctx.Err()
    }
}

func main() {
    ctx, cancel := context.WithCancel(context.Background())
    var numGoroutines = 3

    for i := 0; i < numGoroutines; i++ {
        go func(id int) {
            err := mockAPI(ctx, id)
            if err != nil {
                cancel() // 只要有一个失败,取消所有任务
            }
        }(i)
    }

    // 等待一段时间,确保goroutine有机会开始执行
    time.Sleep(5 * time.Second)
}

超时控制示例

package main

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

// 模拟请求外部API
func mockAPI(ctx context.Context, id int) error {
    select {
    case <-time.After(2 * time.Second): // 模拟API请求时间
        fmt.Printf("goroutine %d success\n", id)
        return nil
    case <-ctx.Done():
        fmt.Printf("goroutine %d cancelled\n", id)
        return ctx.Err()
    }
}

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

    var numGoroutines = 3

    for i := 0; i < numGoroutines; i++ {
        go func(id int) {
            err := mockAPI(ctx, id)
            if err != nil {
                fmt.Printf("goroutine %d failed: %v\n", id, err)
            }
        }(i)
    }

    // 等待一段时间,确保goroutine有机会开始执行
    time.Sleep(5 * time.Second)
}

在上述代码中,context.WithCancel创建了一个可取消的Context,在某个goroutine执行失败时调用cancel函数来取消所有相关的goroutine。而context.WithTimeout则创建了一个带有超时时间的Context,超过设定时间后,所有相关的goroutine会收到取消信号。