MST

星途 面试题库

面试题:Go中如何使用context优雅关闭并发服务

请阐述在Go语言中,如何借助context包来实现优雅关闭一个并发服务,并给出一个简单示例代码,说明主要的实现步骤。
14.1万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

借助context包实现优雅关闭并发服务的方法

  1. 原理

    • context包提供了一种传递截止时间、取消信号和其他请求范围的值的机制,在整个goroutine树中。
    • 通过一个context,可以向所有关联的goroutine发送取消信号,从而实现优雅关闭。
  2. 主要实现步骤

    • 创建一个可取消的context,通常使用context.WithCancelcontext.WithTimeoutcontext.WithDeadline
    • 将这个context传递给需要取消的goroutine
    • goroutine内部,定期检查context的取消信号,例如通过ctx.Done()通道是否关闭。
    • 当收到取消信号时,执行清理操作,然后退出goroutine

示例代码

package main

import (
    "context"
    "fmt"
    "os"
    "os/signal"
    "syscall"
    "time"
)

func worker(ctx context.Context) {
    for {
        select {
        case <-ctx.Done():
            fmt.Println("收到取消信号,开始清理并退出")
            // 在这里执行清理操作,例如关闭数据库连接等
            return
        default:
            fmt.Println("工作中...")
            time.Sleep(1 * time.Second)
        }
    }
}

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

    // 启动一个goroutine
    go worker(ctx)

    // 监听系统信号,如SIGINT(Ctrl+C)或SIGTERM
    sigs := make(chan os.Signal, 1)
    signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)

    go func() {
        sig := <-sigs
        fmt.Println()
        fmt.Println(sig)
        cancel() // 发送取消信号
    }()

    // 防止主函数退出
    select {}
}

在上述代码中:

  1. context.WithCancel创建了一个可取消的context
  2. worker函数在一个无限循环中工作,并通过select语句监听ctx.Done()通道,当该通道关闭时,执行清理操作并退出。
  3. main函数中,通过signal.Notify监听系统信号,当收到SIGINTSIGTERM信号时,调用cancel函数取消context,从而通知worker函数退出。