面试题答案
一键面试实现思路
- 使用context.Context:
context.Context
用于在 goroutine 之间传递截止时间、取消信号等。在主程序中创建一个context.Context
,并将其传递给所有需要监控退出信号的 goroutine。当收到退出通知时,取消这个context.Context
,所有监听此context.Context
的 goroutine 会收到取消信号并优雅退出。 - 资源管理:对于数据库连接、文件句柄等资源,在 goroutine 退出时及时关闭。可以在每个 goroutine 内部使用
defer
语句来确保资源在函数返回时关闭。
代码示例
package main
import (
"context"
"fmt"
"os"
"os/signal"
"syscall"
"time"
)
// 模拟一个使用资源的函数
func worker(ctx context.Context, id int) {
// 模拟数据库连接
fmt.Printf("Worker %d started\n", id)
defer fmt.Printf("Worker %d stopped\n", id)
for {
select {
case <-ctx.Done():
// 收到取消信号,退出循环
return
default:
// 模拟工作
fmt.Printf("Worker %d is working\n", id)
time.Sleep(1 * time.Second)
}
}
}
func main() {
// 创建一个 context.Context 和取消函数
ctx, cancel := context.WithCancel(context.Background())
// 启动多个 goroutine
numWorkers := 3
for i := 0; i < numWorkers; i++ {
go worker(ctx, i)
}
// 监听系统信号,如 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)
// 收到信号,取消 context.Context
cancel()
}()
// 等待所有 goroutine 退出
for {
select {
case <-ctx.Done():
fmt.Println("All workers stopped, exiting main")
return
}
}
}
代码说明
- worker 函数:模拟一个使用资源的 goroutine,在
ctx.Done()
通道接收到信号时退出,确保资源被释放。 - main 函数:
- 创建
context.Context
和取消函数cancel
。 - 启动多个
worker
goroutine,并将ctx
传递给它们。 - 监听系统信号
SIGINT
和SIGTERM
,收到信号时调用cancel
函数取消ctx
。 - 主程序等待所有
worker
goroutine 退出。
- 创建
通过这种方式,可以高效地管理和释放所有正在运行的 goroutine 及其占用的资源,避免性能瓶颈和资源泄漏。