面试题答案
一键面试解决方案
- 使用context.Context:Go语言中的
context.Context
用于在不同的goroutine之间传递截止时间、取消信号等信息。我们可以使用context.Context
来通知各个goroutine需要关闭服务。 - 同步资源清理:使用
sync.WaitGroup
来等待所有资源清理完成,确保没有资源竞争。 - 数据库连接与文件句柄管理:对于数据库连接,可以使用数据库驱动提供的关闭方法;对于文件句柄,使用
os.File
的Close
方法。
代码示例
package main
import (
"context"
"fmt"
"os"
"sync"
"time"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
var (
db *gorm.DB
ctx context.Context
wg sync.WaitGroup
)
func initDB() error {
var err error
dsn := "user:password@tcp(127.0.0.1:3306)/your_database?charset=utf8mb4&parseTime=True&loc=Local"
db, err = gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
return err
}
return nil
}
func main() {
// 初始化数据库连接
if err := initDB(); err != nil {
fmt.Println("Failed to initialize database:", err)
return
}
defer func() {
if db != nil {
sqlDB, _ := db.DB()
sqlDB.Close()
}
}()
// 创建上下文
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// 启动一个goroutine模拟服务
wg.Add(1)
go func() {
defer wg.Done()
for {
select {
case <-ctx.Done():
fmt.Println("Service is shutting down...")
return
default:
// 模拟服务逻辑
fmt.Println("Service is running...")
time.Sleep(1 * time.Second)
}
}
}()
// 模拟文件操作
file, err := os.OpenFile("test.txt", os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
fmt.Println("Failed to open file:", err)
return
}
defer file.Close()
// 模拟运行一段时间后关闭服务
time.Sleep(5 * time.Second)
fmt.Println("Initiating graceful shutdown...")
cancel()
// 等待所有资源清理完成
wg.Wait()
fmt.Println("Service has been gracefully shut down.")
}
在上述代码中:
context.Context
用于通知goroutine关闭服务。sync.WaitGroup
等待服务goroutine完成资源清理。- 数据库连接使用
gorm
库,并在服务结束时关闭连接。 - 文件句柄使用
os.OpenFile
打开,并通过defer
确保在函数结束时关闭。