- 使用 context 包来优雅停止 Goroutine
package main
import (
"context"
"fmt"
"time"
)
func worker(ctx context.Context) {
for {
select {
case <-ctx.Done():
fmt.Println("收到停止信号,退出 Goroutine")
return
default:
fmt.Println("正在工作...")
time.Sleep(1 * time.Second)
}
}
}
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
go worker(ctx)
time.Sleep(5 * time.Second)
}
- 原理:
context
包提供了一种机制来传递截止日期、取消信号和其他请求范围的值给在Goroutine
树中运行的所有Goroutine
。
context.WithTimeout
函数创建了一个带有超时的context
,ctx.Done()
是一个通道,当context
被取消(这里是超时取消)时,该通道会被关闭。
- 在
worker
函数中,通过select
语句监听ctx.Done()
通道,当该通道接收到数据(即通道关闭)时,Goroutine
可以进行清理工作并退出,从而实现优雅停止。
- 使用共享的停止标志
package main
import (
"fmt"
"time"
)
func worker(stop chan struct{}) {
for {
select {
case <-stop:
fmt.Println("收到停止信号,退出 Goroutine")
return
default:
fmt.Println("正在工作...")
time.Sleep(1 * time.Second)
}
}
}
func main() {
stop := make(chan struct{})
go worker(stop)
time.Sleep(3 * time.Second)
close(stop)
time.Sleep(1 * time.Second)
}
- 原理:
- 创建一个
struct{}
类型的通道stop
作为停止标志。
- 在
worker
函数的select
语句中监听stop
通道,当通道关闭时(即close(stop)
被调用),Goroutine
可以感知到并进行相应的清理和退出操作。struct{}
类型的通道占用内存小,因为struct{}
本身不占用任何内存空间,只是用于传递信号。