MST

星途 面试题库

面试题:Go语言Context在链式调用中的传递与取消机制

假设你有一个复杂的业务逻辑,涉及多个函数的链式调用,每个函数都会启动新的goroutine。请详细描述如何正确地在这些函数之间传递Context,以确保当上层Context取消时,所有相关的goroutine都能及时收到取消信号并安全退出。并且说明如何处理传递过程中可能出现的Context值覆盖或丢失等问题。
43.9万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试
  1. Context传递基础
    • 在Go语言中,context.Context是用于在goroutine之间传递截止时间、取消信号和其他请求范围值的主要方式。对于链式调用多个启动新goroutine的函数,要在每个函数调用时传递context.Context
    • 例如,假设我们有函数funcA调用funcBfuncB调用funcC
func funcA(ctx context.Context) {
    funcB(ctx)
}

func funcB(ctx context.Context) {
    funcC(ctx)
}

func funcC(ctx context.Context) {
    go func(ctx context.Context) {
        // 执行具体业务逻辑
        select {
        case <-ctx.Done():
            // 处理取消信号
            return
        default:
            // 正常业务逻辑
        }
    }(ctx)
}
  1. 确保及时取消
    • 在每个启动的goroutine中,使用select语句监听ctx.Done()通道。当ctx.Done()通道接收到数据时,意味着上层Context已取消,此时应尽快清理资源并退出goroutine。
    • 例如,在一个模拟的数据库查询场景中:
func queryDatabase(ctx context.Context) {
    db, err := sql.Open("mysql", "user:password@tcp(127.0.0.1:3306)/test")
    if err!= nil {
        // 处理错误
        return
    }
    defer db.Close()

    rows, err := db.QueryContext(ctx, "SELECT * FROM users")
    if err!= nil {
        // 处理查询错误
        return
    }
    defer rows.Close()

    for rows.Next() {
        select {
        case <-ctx.Done():
            // 清理资源,关闭连接等
            return
        default:
            // 处理查询结果
        }
    }
}
  1. 处理Context值覆盖或丢失问题
    • 值覆盖
      • 确保在函数调用链中,不要意外地重新创建或覆盖context.Context。每个函数应使用接收到的ctx作为参数传递给下一个函数,而不是创建新的ctx。例如,不要在函数内部进行如下错误操作:
func wrongFunc(ctx context.Context) {
    newCtx, cancel := context.WithTimeout(ctx, time.Second)
    defer cancel()
    // 这里应该使用ctx传递给其他函数,而不是newCtx,否则会覆盖上层传递的取消逻辑
    otherFunc(newCtx) 
}
  • 值丢失
    • 要确保在函数调用过程中不会丢失ctx。特别是在使用闭包时,要确保将ctx正确地传递给闭包内部的goroutine。例如:
func correctFunc(ctx context.Context) {
    go func(ctx context.Context) {
        // 正确传递ctx
        subFunc(ctx)
    }(ctx)
}
  • 还可以使用context.Background()作为顶层的Context起点,但在链式调用中,不要轻易在中间替换为context.Background(),除非有明确的业务需求(这种情况很少见)。通常应保持从顶层传递下来的ctx一致性,以确保取消信号能正确传播。