面试题答案
一键面试1. 理解Go上下文(Context)
Go语言中的上下文(context.Context
)主要用于在多个goroutine
之间传递截止时间、取消信号以及其他请求域的数据。它提供了一种安全且简洁的方式来管理goroutine
的生命周期,确保在需要时能够优雅地取消或超时。
2. 处理复杂调度场景的步骤
- 创建上下文:
- 通常在主
goroutine
中创建一个根上下文。可以使用context.Background()
创建一个空的根上下文,它是所有其他上下文的祖先。 - 对于有取消需求的场景,使用
context.WithCancel
创建一个可取消的上下文。对于有超时需求的场景,使用context.WithTimeout
或context.WithDeadline
。
- 通常在主
- 传递上下文:
- 将创建好的上下文作为参数传递给所有需要协作的
goroutine
。这样,当根上下文被取消或超时,所有子goroutine
都能收到相应信号。
- 将创建好的上下文作为参数传递给所有需要协作的
- 监听取消信号:
- 在每个
goroutine
中,通过ctx.Done()
通道监听取消信号。当该通道接收到数据时,意味着上下文被取消,goroutine
应尽快完成当前工作并退出。
- 在每个
- 资源释放:
- 在
goroutine
退出前,确保释放所有已获取的资源,如文件描述符、网络连接等。
- 在
3. 代码示例
package main
import (
"context"
"fmt"
"time"
)
// 模拟一个需要协作完成的任务函数
func worker(ctx context.Context, id int) {
for {
select {
case <-ctx.Done():
// 收到取消信号,清理资源并退出
fmt.Printf("Worker %d received cancel signal, exiting...\n", id)
return
default:
// 执行任务
fmt.Printf("Worker %d is working...\n", id)
time.Sleep(100 * time.Millisecond)
}
}
}
func main() {
// 创建一个可取消的上下文
ctx, cancel := context.WithCancel(context.Background())
// 启动多个goroutine
for i := 1; i <= 3; i++ {
go worker(ctx, i)
}
// 模拟一段时间后取消任务
time.Sleep(500 * time.Millisecond)
fmt.Println("Main: Canceling all workers...")
cancel()
// 等待一段时间,确保所有goroutine都能收到取消信号并退出
time.Sleep(200 * time.Millisecond)
fmt.Println("Main: All workers have been canceled.")
}
在上述代码中:
context.WithCancel(context.Background())
创建了一个可取消的上下文ctx
和取消函数cancel
。worker
函数通过ctx.Done()
监听取消信号,当收到信号时,打印退出信息并返回。- 在
main
函数中,启动了3个worker
goroutine
,500毫秒后调用cancel
函数取消上下文,从而通知所有worker
goroutine
退出。