美文网首页js css html
【Go】优雅上下线(二)

【Go】优雅上下线(二)

作者: 如雨随行2020 | 来源:发表于2022-04-19 02:10 被阅读0次

    @[toc]

    关闭

    上一篇已经讲了如何捕获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()
    }
    

    相关文章

      网友评论

        本文标题:【Go】优雅上下线(二)

        本文链接:https://www.haomeiwen.com/subject/jisraltx.html