面试题答案
一键面试Context包的作用
Context包主要用于在多个goroutine之间传递截止时间、取消信号和其他请求范围的值。它允许对一组相关的goroutine进行集中管理,实现任务取消、超时控制以及传递请求特定的数据。例如在Web服务中,当客户端断开连接时,可以通过Context通知所有相关的goroutine停止工作,避免资源浪费。
并发任务场景下使用Context实现任务取消和超时控制
下面是一个简单示例,模拟多个goroutine同时请求外部API,若其中一个失败则全部取消:
package main
import (
"context"
"fmt"
"net/http"
"time"
)
// 模拟请求外部API
func mockAPI(ctx context.Context, id int) error {
select {
case <-time.After(2 * time.Second): // 模拟API请求时间
fmt.Printf("goroutine %d success\n", id)
return nil
case <-ctx.Done():
fmt.Printf("goroutine %d cancelled\n", id)
return ctx.Err()
}
}
func main() {
ctx, cancel := context.WithCancel(context.Background())
var numGoroutines = 3
for i := 0; i < numGoroutines; i++ {
go func(id int) {
err := mockAPI(ctx, id)
if err != nil {
cancel() // 只要有一个失败,取消所有任务
}
}(i)
}
// 等待一段时间,确保goroutine有机会开始执行
time.Sleep(5 * time.Second)
}
超时控制示例
package main
import (
"context"
"fmt"
"net/http"
"time"
)
// 模拟请求外部API
func mockAPI(ctx context.Context, id int) error {
select {
case <-time.After(2 * time.Second): // 模拟API请求时间
fmt.Printf("goroutine %d success\n", id)
return nil
case <-ctx.Done():
fmt.Printf("goroutine %d cancelled\n", id)
return ctx.Err()
}
}
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
var numGoroutines = 3
for i := 0; i < numGoroutines; i++ {
go func(id int) {
err := mockAPI(ctx, id)
if err != nil {
fmt.Printf("goroutine %d failed: %v\n", id, err)
}
}(i)
}
// 等待一段时间,确保goroutine有机会开始执行
time.Sleep(5 * time.Second)
}
在上述代码中,context.WithCancel
创建了一个可取消的Context,在某个goroutine执行失败时调用cancel
函数来取消所有相关的goroutine。而context.WithTimeout
则创建了一个带有超时时间的Context,超过设定时间后,所有相关的goroutine会收到取消信号。