Golang Go语言中 context 简介(3)-广播通知多个业务 Go 程退出
Golang Go语言中 context 简介(3)-广播通知多个业务 Go 程退出
引
上回聊到,context 是有父子间影响的,父 context cancel 之后,子 context 也会随之 cancel。 这次聊下广播通知多个业务 go 程退出
如何通知多个业务 go 程退出
问题描述
如果在一个业务中会起多个 go 程做一些事,每个 go 程里面会跑流式业务(流式业务可以理解为 dong dong dong 有很多步骤)。你会如何做?
-
基于 bool flag 吗?那你要把所有的 select chan 的地方修改成轮训,改动太大,select 多路复用的优点全没了,引入 cpu 空转。关键有时候还不能这么修改
-
每次退出的时候发个事件到一个专门的 message chan? 基于计算的方式,万一少发了一个,就会造成 go 程泄漏。而且 message chan 的大小也是一个头疼的地方。
-
sync.WaitGroup? WaitGroup 只是 go 程同步等待的函数,不是事件通知用的
基于事件通知的做法
在聊之前,大家估计都知道了两个事情,如果一个 chan 被 close 掉,是可以读取多次的,close 掉一个 close 掉的 chan 是会 panic 的。ok,基于这两点认知,我们设计通知多个业务 go 程的退出代码。
```go
func testQuit(failId int, max int) {
lock := sync.Mutex{}
wg := sync.WaitGroup{}
closeOk := false
done := make(chan struct{})
wg.Add(max)
defer wg.Wait()
for i := 0; i < max; i++ {
go func(id int) {
defer wg.Done()
if id == failId || id == failId-1 {
lock.Lock()
if !closeOk {
close(done)
closeOk = true
}
lock.Unlock()
}
select {
case <-done:
fmt.Printf("id = %d, quit\n", id)
}
}(i)
}
}
我们利用一个 chan 被 close 是可以读取多次的特性,用作广播通知。为了避免一个 chan 会 close 两次会 panic 加入一个 flag 变量。为了 go 程安全,引入 sync.Mutex。
用 context 改造广播通知代码
context 里面实现的代码也是用 close chan 的方式实现的,可能官方看大家都是用这种方式用作广播通知,最后把这种模式加入到了标准库里面
package main
import (
“context”
“fmt”
“sync”
)
func testContext(failId int, max int) {
var wg sync.WaitGroup
ctx, cancel := context.WithCancel(context.Background())
wg.Add(max)
defer wg.Wait()
for i := 0; i < max; i++ {
go func(id int) {
defer wg.Done()
if id == failId {
cancel()
}
select {
case <-ctx.Done():
fmt.Printf("id = %d, quit\n", id)
}
}(i)
}
}
func main() {
testContext(1, 5)
testContext(0, 5)
}
我的 github
更多关于Golang Go语言中 context 简介(3)-广播通知多个业务 Go 程退出的实战教程也可以访问 https://www.itying.com/category-94-b0.html
更多关于Golang Go语言中 context 简介(3)-广播通知多个业务 Go 程退出的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
在Golang(Go语言)中,context
包是一个强大的工具,它不仅用于管理请求的截止日期、取消信号,还能用于广播通知多个业务Go程(goroutine)退出。以下是关于如何使用context
进行广播通知的简要介绍:
context.Broadcast
并不是context
包中直接提供的一个功能,但可以通过context.WithCancel
或context.WithTimeout
等函数结合通道(channel)来实现类似的效果。
-
创建父Context:首先,创建一个父
context
,通常使用context.Background()
或context.TODO()
作为根context
。 -
派生子Context:通过
context.WithCancel
创建一个可以取消的子context
。这个子context
将被多个业务Go程共享。 -
监听取消信号:在每个业务Go程中,使用
select
语句监听子context
的Done
通道。当父context
被取消时,Done
通道会被关闭,触发Go程退出。 -
广播取消:在需要通知所有业务Go程退出时,调用父
context
的取消函数。这将关闭所有派生自该父context
的子context
的Done
通道,从而实现广播通知的效果。
通过这种方式,你可以有效地管理多个业务Go程的生命周期,确保在需要时它们能够优雅地退出。值得注意的是,合理设计context
的传递和使用策略,对于避免资源泄漏和死锁等问题至关重要。