面试题答案
一键面试设计思路
- 信号处理:使用Go的
os/signal
包来捕获系统信号,如os.Interrupt
(通常由用户通过Ctrl+C发送)和syscall.SIGTERM
(用于优雅关闭进程的信号)。 - 共享退出通道:创建一个全局的退出通道(
chan struct{}
),所有协程监听这个通道。当收到退出信号时,向该通道发送一个值,通知所有协程退出。 - 业务逻辑中的退出检查:在每个协程的业务逻辑中,定期检查退出通道是否有值传入。一旦接收到值,立即停止当前业务逻辑,进行资源清理并退出协程。
- 资源清理:在协程退出前,确保所有打开的资源(如文件、数据库连接等)被正确关闭。
关键代码示例
package main
import (
"context"
"fmt"
"os"
"os/signal"
"syscall"
"time"
)
func worker(ctx context.Context, id int) {
for {
select {
case <-ctx.Done():
fmt.Printf("Worker %d received exit signal, cleaning up...\n", id)
// 进行资源清理,如关闭文件、数据库连接等
return
default:
// 模拟复杂业务逻辑和I/O操作
fmt.Printf("Worker %d is working...\n", id)
time.Sleep(1 * time.Second)
}
}
}
func main() {
numWorkers := 3
var ctx context.Context
var cancel context.CancelFunc
ctx, cancel = context.WithCancel(context.Background())
for i := 0; i < numWorkers; i++ {
go worker(ctx, i)
}
sigs := make(chan os.Signal, 1)
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
go func() {
sig := <-sigs
fmt.Println()
fmt.Println(sig)
cancel()
}()
select {}
}
在上述代码中:
worker
函数:模拟了一个协程,它不断检查ctx.Done()
通道。当接收到取消信号时,打印清理信息并退出。main
函数:- 创建了一个可取消的上下文
ctx
和取消函数cancel
。 - 启动多个
worker
协程。 - 使用
signal.Notify
监听系统信号。当接收到SIGINT
或SIGTERM
信号时,调用cancel
函数,向所有协程的ctx.Done()
通道发送取消信号,从而实现所有协程的安全退出。
- 创建了一个可取消的上下文