面试题答案
一键面试实现思路
- 监听Context取消信号:在每个goroutine中,使用
select
语句监听Context.Done()
通道,当接收到取消信号时,及时退出goroutine。 - 处理缓冲区数据:对于有缓冲区的Channel,在goroutine退出前,确保缓冲区中的数据被正确处理。可以将缓冲区数据发送到其他地方(如日志记录、持久化存储等),或者直接丢弃(根据业务需求决定)。
- 安全关闭Channel:确保在关闭Channel之前,所有需要发送的数据都已发送完毕,避免数据丢失。同时,在接收端也要处理好Channel关闭的情况,防止死锁或未定义行为。
关键代码片段
package main
import (
"context"
"fmt"
"time"
)
func worker(ctx context.Context, in <-chan int, out chan<- int) {
defer close(out)
for {
select {
case <-ctx.Done():
// 处理缓冲区剩余数据,这里简单丢弃
for len(in) > 0 {
<-in
}
return
case data, ok := <-in:
if!ok {
return
}
// 模拟数据处理
result := data * 2
select {
case out <- result:
case <-ctx.Done():
// 处理缓冲区剩余数据,这里简单丢弃
for len(out) > 0 {
<-out
}
return
}
}
}
}
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
in := make(chan int)
out := make(chan int)
go worker(ctx, in, out)
// 发送数据
go func() {
for i := 0; i < 10; i++ {
select {
case in <- i:
case <-ctx.Done():
return
}
}
close(in)
}()
// 接收结果
for result := range out {
fmt.Println("Result:", result)
if ctx.Err() != nil {
break
}
}
// 等待所有goroutine完成
time.Sleep(1 * time.Second)
}
在上述代码中:
worker
函数通过select
语句监听ctx.Done()
通道,当接收到取消信号时,清理in
通道的缓冲区数据并退出。- 在数据处理部分,
select
语句用于在发送结果到out
通道和处理取消信号之间进行选择。如果接收到取消信号,清理out
通道的缓冲区数据并退出。 - 在主函数中,使用
context.WithTimeout
创建一个带有超时的Context
,通过cancel
函数可以手动取消。在发送数据和接收结果时,都考虑了Context
取消的情况,确保资源的正确释放。