当前位置:   article > 正文

golang 使用ctx优雅退出程序解决方案_ctx 信号 csdn

ctx 信号 csdn

项目场景:

项目需要使用信号进行优雅的退出(即主协程在所有协程退出之后再退出)


问题描述:

该问题是预防协程泄露的解决方案之一,下面demo 使用 signal 信号信道,来监测程序是否被信号中断,使用WaitGroup 来等待子协程全部回收后主协程退出,使用ctx + select来传递子协程的退出信号


解决方案:

该问题是预防协程泄露的解决方案之一,下面demo 使用 signal 信号信道,来监测程序是否被信号中断,使用WaitGroup 来等待子协程全部回收后主协程退出,使用ctx + select来传递子协程的退出信号

package main

import (
        "context"
        "fmt"
        "os"
        "os/signal"
        "sync"
        "syscall"
        "time"
)

var gctx = context.Background()
var wg sync.WaitGroup

// 凌晨定时处理删除任务
func TimeToDelDb(ctx context.Context) {
        for {
                now := time.Now()
                next := now.Add(time.Hour * 24)                                                      //通过now偏移24小时
                next = time.Date(next.Year(), next.Month(), next.Day(), 0, 0, 0, 0, next.Location()) //获取下一个凌晨的日期
                t := time.NewTimer(next.Sub(now))                           //计算当前时间到凌晨的时间间隔,设置一个定时器
                select {
                case <-t.C:
                        // 执行删除任务
                case <-ctx.Done():
                        fmt.Println("ctx stop")
                        wg.Done()
                        return
                }
        }
}

func main() {
        sigs := make(chan os.Signal, 1)
        signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM, syscall.SIGKILL, syscall.SIGQUIT)
        ctx, cancel := context.WithCancel(gctx)
        wg.Add(2)
        go TimeToDelDb(ctx)
        ticker := time.NewTicker(3 * time.Second) // 运行时长

        go func() {
                for {
                        select {
                        case <-ticker.C:
                                // 执行xx任务
                        case <-sigs:
                                fmt.Println("signal stop")
                                wg.Done()
                                cancel()
                        }
                }
                defer ticker.Stop()
        }()
        wg.Wait()
        fmt.Println("Progress stop")
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57

方案2

减少部分不需要的协程
select 中 使用break只能跳出select 使用return 走不到waitgroup 里面

package main

import (
    "context"
    "fmt"
    "os"
    "os/signal"
    "sync"
    "syscall"
    "time"
)

var gctx = context.Background()
var wg sync.WaitGroup

// 凌晨定时处理删除任务
func TimeToDelDb(ctx context.Context) {
    for {
        now := time.Now()
        next := now.Add(time.Hour * 24)                                                      //通过now偏移24小时
        next = time.Date(next.Year(), next.Month(), next.Day(), 0, 0, 0, 0, next.Location()) //获取下一个凌晨的日期
        t := time.NewTimer(next.Sub(now))                                                    //计算当前时间到凌晨的时间间隔,设置一个定时器
        select {
        case <-t.C:
            // 执行删除任务
        case <-ctx.Done():
            fmt.Println("ctx stop")
            wg.Done()
            return
        }
    }
}

func main() {
    sigs := make(chan os.Signal, 1)
    signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM, syscall.SIGKILL, syscall.SIGQUIT)
    ctx, cancel := context.WithCancel(gctx)
    wg.Add(1)
    go TimeToDelDb(ctx)
    ticker := time.NewTicker(3 * time.Second) // 运行时长

    for {
        select {
        case <-ticker.C:
            // 执行xx任务
        case <-sigs:
            cancel()
            fmt.Println("signal stop")
            goto Exit
        }
    }
    defer ticker.Stop()
Exit:
    wg.Wait()
    fmt.Println("Progress stop")
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57

运行结果

user@dev:~$ go run test.go
^Csignal stop
ctx stop
Progress stop
user@dev:~$

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/507432
推荐阅读
相关标签
  

闽ICP备14008679号