MST

星途 面试题库

面试题:Go中context如何用于管理单个goroutine的异步操作状态同步

在Go语言中,假设你有一个简单的异步任务在goroutine中执行,例如从数据库读取数据。请描述如何使用context来管理这个goroutine的取消操作以及如何传递截止时间信息,并且给出相应的代码示例。
29.5万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试
  1. 使用context管理goroutine取消操作及传递截止时间信息的原理

    • context包提供了一种优雅的方式来管理goroutine的生命周期。context.Context类型被设计为携带截止时间、取消信号及其他请求范围的值,这些值可以在goroutine树中传递。
    • context.WithCancel函数用于创建一个可取消的context,调用返回的取消函数可以取消这个context,所有基于这个context派生的子context也会被取消。
    • context.WithTimeout函数用于创建一个带有超时的context,在指定的时间后会自动取消,也可以通过调用返回的取消函数提前取消。
  2. 代码示例

package main

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

// 模拟从数据库读取数据的函数
func readDataFromDB(ctx context.Context) error {
    // 模拟一个长时间运行的任务
    select {
    case <-time.After(5 * time.Second):
        // 这里模拟数据库读取操作完成
        return nil
    case <-ctx.Done():
        // 如果context被取消,返回取消错误
        return ctx.Err()
    }
}

func main() {
    // 创建一个带有2秒超时的context
    ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
    defer cancel() // 确保函数结束时取消context,释放资源

    err := readDataFromDB(ctx)
    if err != nil {
        fmt.Printf("操作被取消或超时: %v\n", err)
    } else {
        fmt.Println("数据读取成功")
    }
}

在上述代码中:

  • context.WithTimeout(context.Background(), 2*time.Second)创建了一个带有2秒超时的context
  • readDataFromDB函数内部使用select语句监听time.After(5 * time.Second)(模拟数据库读取操作完成)和ctx.Done()context被取消的信号)。
  • 如果context在数据库读取操作完成前被取消(这里是超时取消),ctx.Done()通道会收到信号,函数返回取消错误。如果数据库读取操作在context取消前完成,函数返回nil