面试题答案
一键面试基本原理
在Go语言中,context
包提供了一种机制,用于在多个goroutine
之间传递截止时间、取消信号、请求作用域的值等相关上下文信息。其核心在于,一个context
对象可以被传递到不同的goroutine
中,这些goroutine
可以监听该context
的取消信号或截止时间等。当父goroutine
取消context
或者context
的截止时间到达时,所有基于该context
派生的子goroutine
会收到相应的取消通知,从而可以进行清理工作并退出,避免资源泄漏。
实现方式
- 创建
context
:- 可以使用
context.Background()
创建一个空的根context
,这通常是所有context
树的根节点。 context.TODO()
用于当不清楚当前context
应该使用什么时的占位符。- 使用
context.WithCancel(parent)
、context.WithDeadline(parent, d)
、context.WithTimeout(parent, timeout)
等函数基于一个父context
创建派生的context
。例如,context.WithCancel
用于创建一个可取消的context
,context.WithDeadline
和context.WithTimeout
用于创建带有截止时间的context
。
- 可以使用
- 传递
context
:将创建好的context
传递给需要的goroutine
。 - 监听取消信号:在
goroutine
中通过ctx.Done()
通道监听取消信号。当context
被取消时,该通道会被关闭。
代码示例
package main
import (
"context"
"fmt"
"time"
)
func worker(ctx context.Context) {
for {
select {
case <-ctx.Done():
fmt.Println("收到取消信号,退出")
return
default:
fmt.Println("工作中...")
time.Sleep(1 * time.Second)
}
}
}
func main() {
ctx, cancel := context.WithCancel(context.Background())
go worker(ctx)
time.Sleep(3 * time.Second)
cancel()
time.Sleep(1 * time.Second)
}
在上述代码中:
- 首先使用
context.WithCancel(context.Background())
创建了一个可取消的context
和对应的取消函数cancel
。 - 启动一个
goroutine
执行worker
函数,并将ctx
传递进去。 - 在
worker
函数中,通过select
语句监听ctx.Done()
通道,当接收到取消信号时,打印信息并退出循环。 - 在
main
函数中,等待3秒后调用cancel
函数取消context
,worker
函数中的goroutine
会收到取消信号并退出。