面试题答案
一键面试- 使用
context.WithTimeout
创建带超时的context
:
这里创建了一个ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel()
ctx
,它在10秒后会自动取消,cancel
函数用于手动取消(如果需要提前取消的话),使用defer
确保函数结束时一定会调用cancel
,防止资源泄漏。 - 在并发请求处理函数中传递
context
:
这里var wg sync.WaitGroup for _, url := range urls { wg.Add(1) go func(u string) { defer wg.Done() processURL(ctx, u) }(url) } wg.Wait()
processURL
函数接收ctx
作为参数,wg
用于等待所有并发任务完成。 - 在
processURL
函数中处理资源操作:func processURL(ctx context.Context, url string) { // 打开文件句柄 file, err := os.OpenFile("log.txt", os.O_CREATE|os.O_WRONLY, 0644) if err!= nil { log.Println("Failed to open file:", err) return } defer file.Close() // 建立数据库连接(示例,实际需要根据具体数据库驱动调整) db, err := sql.Open("mysql", "user:password@tcp(127.0.0.1:3306)/database") if err!= nil { log.Println("Failed to connect to database:", err) return } defer db.Close() // 模拟请求 req, err := http.NewRequestWithContext(ctx, "GET", url, nil) if err!= nil { log.Println("Failed to create request:", err) return } resp, err := http.DefaultClient.Do(req) if err!= nil { if ctx.Err() == context.DeadlineExceeded { log.Println("Request timed out") } else { log.Println("Failed to do request:", err) } return } defer resp.Body.Close() // 处理响应数据,写入文件等操作 //... }
- 在打开文件句柄和建立数据库连接后,使用
defer
语句确保函数结束时文件和数据库连接会被关闭。 - 在发起HTTP请求时,使用
http.NewRequestWithContext
将ctx
传递进去,这样如果ctx
超时,请求也会被取消。 - 当发生错误时,检查
ctx.Err()
是否为context.DeadlineExceeded
,如果是,则表示是超时错误,做相应处理。
- 在打开文件句柄和建立数据库连接后,使用
通过上述步骤,利用context
的超时机制,结合defer
语句关闭资源,可以确保在超时发生时,所有已经打开的资源能够被正确关闭和释放,避免资源泄漏。