【Go】优雅上下线(二)

本文探讨在Go中如何在多个协程环境下优雅地关闭程序。主要内容包括:子协程通过Channel关闭机制接收关闭信号,主协程使用sync.WaitGroup等待所有子协程完成,以及限制并发协程数的GoLimit工具类的实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

关闭

上一篇已经讲了如何捕获Unix信号,这一篇我们来探究一下在多个协程工作的情况下如何正确关闭程序。一般在项目中不会仅一个协程处理任务,而是主协程做完初始化后,启动若干个子协程去处理各自的业务,甚至子协程继续开启子协程。
如此一来,在关闭程序就有两个问题需要解决:

  1. 子协程如何收到关闭信号
  2. 主协程如何知道所有子协程都完成了
    主协程需要等待所有子协程都完成后才能退出,因为主协程退出后,子协程会被强制关闭。

准确来说,第二个是比较常见的问题,不仅限于今天要讲的优雅上下线

一、子协程关闭

在Go中,对一个已经关闭的Channel取值是可以的,所以子协程可以调用上一篇【Go】优雅上下线(一)监控协程中的Closed()直接获取是否收到Unix信号或者调用GetStopChan()拿到stop通道自己监听。这两种方式基本能解决问题一

二、主协程等待所有子协程关闭

官方推荐使用sync.WaitGroup


import "fmt"
import "time"
import "sync"

func main() {
    var wg sync.WaitGroup

    for i := 0; i < 10; i++ {
        wg.Add(1)
        go func(i int) {
            defer wg.Done()
            time.Sleep(1 * time.Second)
            fmt.Println(i)
        }(i)
    }
    wg.Wait() // 等待
    fmt.Println("main exit")
}

三、对子协程个数的限制

在解决优雅上下线这个问题时,突然看到我导师之前写过的一个工具类,这个工具类可以限制一个同步任务中并发的协程数,同时还可以保证Wait所有子协程完成

// GoLimit 限制一个同步任务中并发的协程数
type GoLimit struct {
	size int
	c    chan struct{}
	wg   *sync.WaitGroup
}

func NewGoLimit(size int) *GoLimit {
	return &GoLimit{
		size: size,
		c:    make(chan struct{}, size),
		wg:   &sync.WaitGroup{},
	}
}

func (g *GoLimit) Run(f func()) {
	g.wg.Add(1)
	g.c <- struct{}{}
	go func() {
		f()
		g.wg.Done()
		<-g.c
	}()
}

func (g *GoLimit) Wait() {
	g.wg.Wait()
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值