MST

星途 面试题库

面试题:Go中Goroutine生命周期管理之基础

在Go语言中,如何优雅地停止一个Goroutine?请举例说明,并解释使用这种方式的原理。
38.2万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试
  1. 使用 context 包来优雅停止 Goroutine
    • 示例代码
package main

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

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

func main() {
    ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
    defer cancel()

    go worker(ctx)

    time.Sleep(5 * time.Second)
}
  • 原理
    • context包提供了一种机制来传递截止日期、取消信号和其他请求范围的值给在Goroutine树中运行的所有Goroutine
    • context.WithTimeout函数创建了一个带有超时的contextctx.Done()是一个通道,当context被取消(这里是超时取消)时,该通道会被关闭。
    • worker函数中,通过select语句监听ctx.Done()通道,当该通道接收到数据(即通道关闭)时,Goroutine可以进行清理工作并退出,从而实现优雅停止。
  1. 使用共享的停止标志
    • 示例代码
package main

import (
    "fmt"
    "time"
)

func worker(stop chan struct{}) {
    for {
        select {
        case <-stop:
            fmt.Println("收到停止信号,退出 Goroutine")
            return
        default:
            fmt.Println("正在工作...")
            time.Sleep(1 * time.Second)
        }
    }
}

func main() {
    stop := make(chan struct{})

    go worker(stop)

    time.Sleep(3 * time.Second)
    close(stop)
    time.Sleep(1 * time.Second)
}
  • 原理
    • 创建一个struct{}类型的通道stop作为停止标志。
    • worker函数的select语句中监听stop通道,当通道关闭时(即close(stop)被调用),Goroutine可以感知到并进行相应的清理和退出操作。struct{}类型的通道占用内存小,因为struct{}本身不占用任何内存空间,只是用于传递信号。