MST

星途 面试题库

面试题:Go中如何利用context实现通知退出机制保障并发程序的优雅关停

请详细描述在Go语言中,如何使用context包来实现通知退出机制,以确保并发程序在接收到退出信号时能够优雅关停。例如,假设有多个goroutine在执行不同任务,如何通过context来协调它们的退出,给出具体代码示例并解释每一步的作用。
39.7万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

在Go语言中,context包主要用于在多个goroutine之间传递截止时间、取消信号以及其他请求域的值。以下是使用context包实现通知退出机制,确保并发程序优雅关停的详细步骤和代码示例:

  1. 创建一个context对象:一般使用context.Background()作为根context,然后基于它衍生出带有取消功能的context
  2. 传递context到各个goroutine:每个需要监听退出信号的goroutine都应该接受这个context
  3. goroutine中监听取消信号:使用contextDone()通道来监听取消信号,一旦接收到信号,就停止当前goroutine的工作。
  4. 发送取消信号:在主程序中,当需要退出时,调用取消函数来发送取消信号。

以下是具体的代码示例:

package main

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

func worker(ctx context.Context, id int) {
    for {
        select {
        case <-ctx.Done():
            // 当接收到取消信号时,退出循环
            fmt.Printf("Worker %d stopped\n", id)
            return
        default:
            // 模拟工作
            fmt.Printf("Worker %d is working\n", id)
            time.Sleep(1 * time.Second)
        }
    }
}

func main() {
    // 创建一个可取消的context
    ctx, cancel := context.WithCancel(context.Background())

    // 启动多个goroutine
    numWorkers := 3
    for i := 1; i <= numWorkers; i++ {
        go worker(ctx, i)
    }

    // 模拟主程序工作一段时间
    time.Sleep(3 * time.Second)

    // 发送取消信号
    cancel()

    // 等待所有goroutine退出
    time.Sleep(2 * time.Second)
    fmt.Println("All workers stopped, program exiting")
}

代码解释

  1. worker函数

    • 接受一个context.Context类型的参数ctx和一个表示worker编号的id
    • for循环中,使用select语句监听ctx.Done()通道。当ctx.Done()通道接收到数据时,说明取消信号已发出,worker打印停止信息并返回,结束goroutine
    • default分支中,模拟worker的工作,每秒打印一次工作信息。
  2. main函数

    • 使用context.WithCancel(context.Background())创建一个可取消的context,并返回ctxcancel函数。ctx用于传递取消信号到各个goroutinecancel函数用于手动发送取消信号。
    • 启动多个worker goroutine,并传递ctx
    • 主程序休眠3秒模拟工作,之后调用cancel()函数发送取消信号。
    • 再休眠2秒,确保所有goroutine有足够时间接收到取消信号并退出,最后打印程序退出信息。