MST

星途 面试题库

面试题:Go中context如何在父子goroutine间传递上下文信息

请阐述在Go语言中,使用context在父子goroutine之间传递上下文切换相关信息的基本原理与实现方式,并举一个简单的代码示例说明。
29.4万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

基本原理

在Go语言中,context包提供了一种机制,用于在多个goroutine之间传递截止时间、取消信号、请求作用域的值等相关上下文信息。其核心在于,一个context对象可以被传递到不同的goroutine中,这些goroutine可以监听该context的取消信号或截止时间等。当父goroutine取消context或者context的截止时间到达时,所有基于该context派生的子goroutine会收到相应的取消通知,从而可以进行清理工作并退出,避免资源泄漏。

实现方式

  1. 创建context
    • 可以使用context.Background()创建一个空的根context,这通常是所有context树的根节点。
    • context.TODO()用于当不清楚当前context应该使用什么时的占位符。
    • 使用context.WithCancel(parent)context.WithDeadline(parent, d)context.WithTimeout(parent, timeout)等函数基于一个父context创建派生的context。例如,context.WithCancel用于创建一个可取消的contextcontext.WithDeadlinecontext.WithTimeout用于创建带有截止时间的context
  2. 传递context:将创建好的context传递给需要的goroutine
  3. 监听取消信号:在goroutine中通过ctx.Done()通道监听取消信号。当context被取消时,该通道会被关闭。

代码示例

package main

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

func worker(ctx context.Context) {
    for {
        select {
        case <-ctx.Done():
            fmt.Println("收到取消信号,退出")
            return
        default:
            fmt.Println("工作中...")
            time.Sleep(1 * time.Second)
        }
    }
}

func main() {
    ctx, cancel := context.WithCancel(context.Background())
    go worker(ctx)

    time.Sleep(3 * time.Second)
    cancel()
    time.Sleep(1 * time.Second)
}

在上述代码中:

  1. 首先使用context.WithCancel(context.Background())创建了一个可取消的context和对应的取消函数cancel
  2. 启动一个goroutine执行worker函数,并将ctx传递进去。
  3. worker函数中,通过select语句监听ctx.Done()通道,当接收到取消信号时,打印信息并退出循环。
  4. main函数中,等待3秒后调用cancel函数取消contextworker函数中的goroutine会收到取消信号并退出。