golang优雅的结束协程
在 Go 语言里,协程(goroutine)本身没有内置的停止机制,不过可以借助一些技巧和工具来实现协程的停止,主要有三种方式。
1. 使用 context
包
context
包为在 Go 程序中传递请求范围的数据、取消信号和截止时间等提供了一种方式。可以利用 context
中的 WithCancel
函数创建一个可取消的上下文,进而实现协程的停止。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()) //context.WithCancel
函数会创建一个可取消的上下文ctx
以及一个取消函数cancel
。
go worker(ctx) // 模拟一段时间后停止协程 time.Sleep(5 * time.Second) cancel() // 等待一段时间,确保协程有机会停止 time.Sleep(2 * time.Second) }
2、使用通道
可以借助通道来向协程发送停止信号。示例如下:
package main import ( "fmt" "time" ) func worker(stop chan bool) { for { select { case <-stop: fmt.Println("协程停止") return default: fmt.Println("协程正在工作...") time.Sleep(1 * time.Second) } } } func main() { stop := make(chan bool) go worker(stop) // 模拟一段时间后停止协程 time.Sleep(5 * time.Second) stop <- true // 等待一段时间,确保协程有机会停止 time.Sleep(2 * time.Second) }
3. 利用共享变量
可以使用一个共享的布尔变量来控制协程的停止。示例如下:
package main import ( "fmt" "sync" "time" ) var ( stopFlag bool mu sync.Mutex ) func worker() { for { mu.Lock() if stopFlag { mu.Unlock() fmt.Println("协程停止") return } mu.Unlock() fmt.Println("协程正在工作...") time.Sleep(1 * time.Second) } } func main() { go worker() // 模拟一段时间后停止协程 time.Sleep(5 * time.Second) mu.Lock() stopFlag = true mu.Unlock() // 等待一段时间,确保协程有机会停止 time.Sleep(2 * time.Second) }