GOLANG context包

学习golang绕不开并发,本身提供的goroutine搭配上chanel十分好用,但是总是有一些特殊情况,如果要再一定时间内返回结果而goroutine又没有像c的线程一样提供主动结束子进程的方法。
之前自己遇到这种情况的时候也找了一些资料,就用标准库自己写了一个超时,大致是这样的

    for i := 0; i < len(data.Data); i++ {
        select {
        case data := <-c:
            /* 处理数据*/
        case <-time.After(200 * time.Millisecond):
            /* 已超时 返回 */
            break
        }
    }

自己用用是够了,需要知道自己创建了多少个goroutines,不然会造成不必要的延迟。
然后最近看了gogstash的源码。。。(看完后觉得自己写的真烂
里面有一些常用的第三方库,context就是其中一个,好像还是谷歌自己内部人员写的。。
有了这个写超时就简单很多了
示例看下面的代码吧。

package main
import (
    "fmt"
    "time"
    "golang.org/x/net/context"
)
// 模拟一个最小执行时间的阻塞函数
func inc(a int) int {
    res := a + 1                // 虽然我只做了一次简单的 +1 的运算,
    time.Sleep(1 * time.Second) //强行超时
    return res
}

// 如果计算被中断, 则返回 -1
func Add(ctx context.Context, a, b int) int {
    res := 0
    for i := 0; i < a; i++ {
        res = inc(res)
        select {
        case <-ctx.Done():
            return -1
        default:
        // 没有结束 ... 执行 ...
        }
    }
    for i := 0; i < b; i++ {
        res = inc(res)
        select {
        case <-ctx.Done():
            return -1
        default:
        // 没有结束 ... 执行 ...
        }
    }
    return res
}
func main() {
    {
        // 使用开放的 API 计算 a+b
        a := 1
        b := 2
        timeout := 2 * time.Second
        ctx, _ := context.WithTimeout(context.Background(), timeout)
        res := Add(ctx, 1, 2)
        fmt.Printf("Compute: %d+%d, result: %d\n", a, b, res)
    }
    {
        // 手动取消
        a := 1
        b := 2
        ctx, cancel := context.WithCancel(context.Background())
        go func() {
            time.Sleep(2 * time.Second)
            cancel() // 在调用处主动取消
        }()
        res := Add(ctx, 1, 2)
        fmt.Printf("Compute: %d+%d, result: %d\n", a, b, res)
    }
}

(网上找的)

用起来是很简单的,创建一个context,和参数一起传入,超时之后ctx.Done()就会返回一个信号,然后就可以把这个goroutine终止掉了。

在gogstash里作者还这个和信号量绑定在一起,用这个函数

func contextWithOSSignal(parent context.Context, logger logutil.LevelLogger, sig ...os.Signal) context.Context {
    osSignalChan := make(chan os.Signal, 1)
    signal.Notify(osSignalChan, sig...)

    ctx, cancel := context.WithCancel(parent)

    go func(cancel context.CancelFunc) {
        select {
        case sig := <-osSignalChan:
            logger.Info(sig)
            cancel()
        }
    }(cancel)

    return ctx
}

当程序被杀死时能安全的退出。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值