面试题答案
一键面试使用Context管理goroutine生命周期及避免资源泄露思路
- 创建Context:在主goroutine中创建一个顶层的
Context
,通常使用context.Background()
作为根Context
,然后基于它衍生出带有取消功能或超时功能的Context
。 - 传递Context:将这个
Context
传递给所有需要管理生命周期的goroutine。每个goroutine在执行任务时,要定期检查Context
的取消信号。 - 取消操作:当需要结束这些goroutine时,调用取消函数(由
context.WithCancel
或context.WithTimeout
返回的取消函数),所有接收该Context
的goroutine会收到取消信号,从而安全地退出。
确保数据库连接在超时时正确关闭思路
- 使用带超时的Context:在连接数据库的goroutine中,使用
context.WithTimeout
创建一个带超时的Context
。 - 连接数据库:使用这个带超时的
Context
来执行数据库连接操作。 - 检查超时:在连接操作过程中,定期检查
Context
的状态。如果超时,取消数据库连接操作,并关闭已建立的连接(如果有)。
关键代码片段
package main
import (
"context"
"fmt"
"net/http"
"time"
)
func connectDB(ctx context.Context) error {
// 创建一个模拟的数据库连接
// 这里使用time.Sleep模拟连接操作耗时
select {
case <-time.After(2 * time.Second):
fmt.Println("Database connection established")
return nil
case <-ctx.Done():
fmt.Println("Database connection timed out")
// 这里假设已经有连接建立,进行关闭操作
// 实际应用中需根据具体数据库连接库实现
return ctx.Err()
}
}
func worker(ctx context.Context) {
err := connectDB(ctx)
if err != nil {
fmt.Printf("Worker failed: %v\n", err)
}
}
func main() {
// 创建一个带超时的Context
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
defer cancel()
// 启动goroutine
go worker(ctx)
// 主线程等待一段时间
time.Sleep(3 * time.Second)
}
在上述代码中:
connectDB
函数模拟连接数据库操作,使用select
语句监听time.After
和ctx.Done()
信号,以处理超时情况。worker
函数调用connectDB
,并处理连接过程中的错误。main
函数创建一个带1秒超时的Context
,启动worker
goroutine,主线程等待3秒以观察结果。