Better late than never.

使用golang的context 来停止正在运行的 goroutine

参考文章 https://www.flysnow.org/2017/05/12/go-in-action-go-context.html

package main

import (
    "context"
    "log"
    "time"
)

// 定义 Context 接口,用于主动停止正在运行的 goroutine
type ContextInterFace interface {
    main()
}

// 使用 channel + select 的方式实现停止运行中的 goroutine
type ChanSelect struct {
    ContextInterFace
}

// 使用 context 的方式实现停止运行中的 goroutine
type ContextEntity struct {
    ContextInterFace
}

// 使用 context 的方式实现停止运行中的 多个 goroutine
type Multiple struct {
    ContextInterFace
}

func (c *ChanSelect) main() {

    // make 一个用于停止 goroutine 的 channel
    stop := make(chan bool)

    go func() {
        for {
            select {
            case <-stop: // channel 只要能取出就停止
                log.Println("监控退出,停止了...")
                return
            default:
                log.Println("goroutine监控中...")
                time.Sleep(2 * time.Second)
            }
        }
    }()

    time.Sleep(10 * time.Second)
    log.Println("可以了,通知监控停止")

    // 发送停止 goroutine 的信号
    stop <- true
    // 为了检测监控过是否停止,如果没有监控输出,就表示停止了
    time.Sleep(5 * time.Second)

    log.Println("来自 ChanSelect")
}

func (c *ContextEntity) main() {

    ctx, cancel := context.WithCancel(context.Background())
    go func(ctx context.Context) {
        for {
            select {
            case <-ctx.Done():
                log.Println("监控退出,停止了...")
                return
            default:
                log.Println("goroutine监控中...")
                time.Sleep(2 * time.Second)
            }
        }
    }(ctx)

    time.Sleep(10 * time.Second)
    log.Println("可以了,通知监控停止")

    // 发送停止 goroutine 的信号
    cancel()
    //为了检测监控过是否停止,如果没有监控输出,就表示停止了
    time.Sleep(5 * time.Second)

    log.Println("来自 ContextEntity")
}

func (c *Multiple) main() {
    ctx, cancel := context.WithCancel(context.Background())

    // 所有goroutine 都传入 Context 进行跟踪
    go watch(ctx, "【监控1】")
    go watch(ctx, "【监控2】")
    go watch(ctx, "【监控3】")

    time.Sleep(10 * time.Second)
    log.Println("可以了,通知监控停止")

    // 所有衍生的context收到cancel信号,所监控的goroutine都会停止
    cancel()
    //为了检测监控过是否停止,如果没有监控输出,就表示停止了
    time.Sleep(5 * time.Second)

    log.Println("来自 Multiple")
}

func watch(ctx context.Context, name string) {
    for {
        select {
        case <-ctx.Done():
            log.Println(name, "监控退出,停止了...")
            return
        default:
            log.Println(name, "goroutine监控中...")
            time.Sleep(2 * time.Second)
        }
    }
}

func main() {
    //ContextInterFace.main(&ChanSelect{})
    //ContextInterFace.main(&ContextEntity{})
    // todo 可以停止正在运行的goroutine,那么可以继续开启之前停止的 goroutine 吗
    ContextInterFace.main(&Multiple{})
}

-- END

写的不错,赞助一下主机费

扫一扫,用支付宝赞赏
扫一扫,用微信赞赏

暂无评论~~