面试题答案
一键面试- 优雅停止Goroutine的方法:
- 使用上下文(
context
):context
包提供了一种取消Goroutine的方法,它可以在多个Goroutine之间传递取消信号,并且在取消时清理相关资源。context
主要有context.Background
、context.WithCancel
、context.WithDeadline
、context.WithTimeout
等函数来创建不同类型的上下文。 - 使用通道(
channel
):通过向Goroutine发送一个信号(比如一个布尔值)来通知它停止。当Goroutine接收到这个信号时,它会停止执行循环并清理资源。
- 使用上下文(
- 代码示例(使用通道):
package main
import (
"fmt"
"time"
)
func main() {
stopCh := make(chan struct{})
go func() {
for {
select {
case <-stopCh:
fmt.Println("Goroutine stopped")
return
default:
// 模拟从网络读取数据的长时间运行操作
fmt.Println("Reading data from network...")
time.Sleep(1 * time.Second)
}
}
}()
// 模拟一段时间后停止Goroutine
time.Sleep(3 * time.Second)
close(stopCh)
time.Sleep(1 * time.Second) // 等待Goroutine完全停止
}
- 代码示例(使用上下文):
package main
import (
"context"
"fmt"
"time"
)
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
go func(ctx context.Context) {
for {
select {
case <-ctx.Done():
fmt.Println("Goroutine stopped")
return
default:
// 模拟从网络读取数据的长时间运行操作
fmt.Println("Reading data from network...")
time.Sleep(1 * time.Second)
}
}
}(ctx)
time.Sleep(5 * time.Second)
}
在上述代码中:
- 使用通道的示例:通过
stopCh
通道来通知Goroutine停止。select
语句中的default
分支模拟从网络读取数据的操作,当stopCh
接收到信号时(通过close(stopCh)
关闭通道),Goroutine会停止运行。 - 使用上下文的示例:通过
context.WithTimeout
创建了一个带有超时的上下文ctx
,cancel
函数用于手动取消上下文(虽然在这个例子中没有手动调用cancel
,因为设置了超时)。在Goroutine内部,select
语句监听ctx.Done()
通道,当接收到取消信号时,Goroutine停止运行。