• Go协程超时退出的三种方式


    主要介绍如何实现超时控制,主要有三种

    1、context.WithTimeout/context.WithDeadline + time.After

    2、context.WithTimeout/context.WithDeadline + time.NewTimer

    3、channel + time.After/time.NewTimer

    context.WithTimeout + time.After
    func AsyncCall() {
    ctx, cancel := context.WithTimeout(context.Background(), time.Duration(time.Millisecond*800))
    defer cancel()

    go func(ctx context.Context) {
    // 发送HTTP请求
    }()

    select {
    case <-ctx.Done():
    fmt.Println("call successfully!!!")
    return
    case <-time.After(time.Duration(time.Millisecond * 900)):
    fmt.Println("timeout!!!")
    return
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    通过context的WithTimeout设置一个有效时间为800毫秒的context
    该context会在耗尽800毫秒后或者方法执行完成后结束,结束的时候会向通道ctx.Done发送信号
    Done通道负责监听context啥时候结束,如果在time.After设置的超时时间到了,你还没完事,那我就不等了,执行超时后的逻辑代码。
    还要加上这个time.After呢?
    这是因为该方法内的context是自己申明的,可以手动设置对应的超时时间,但是在大多数场景,这里的ctx是从上游一直传递过来的,对于上游传递过来的context还剩多少时间,我们是不知道的,所以这时候通过time.After设置一个自己预期的超时时间就很有必要了。
    context.WithTimeout + time.NewTimer
    func AsyncCall() {
    ctx, cancel := context.WithTimeout(context.Background(), time.Duration(time.Millisecond * 800))
    defer cancel()
    timer := time.NewTimer(time.Duration(time.Millisecond * 900))

    go func(ctx context.Context) {
    // 发送HTTP请求
    }()

    select {
    case <-ctx.Done():
    timer.Stop()
    timer.Reset(time.Second)
    fmt.Println("call successfully!!!")
    return
    case <-timer.C:
    fmt.Println("timeout!!!")
    return
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    这里的主要区别是将time.After换成了time.NewTimer,也是同样的思路如果接口调用提前完成,则监听到Done信号,然后关闭定时器。否则的话,会在指定的timer即900毫秒后执行超时后的业务逻辑。
    channel + time.After/time.NewTimer
    func AsyncCall() {
    ctx := context.Background()
    done := make(chan struct{}, 1)

    go func(ctx context.Context) {
    // 发送HTTP请求
    done <- struct{}{}
    }()

    select {
    case <-done:
    fmt.Println("call successfully!!!")
    return
    case <-time.After(time.Duration(800 * time.Millisecond)):
    fmt.Println("timeout!!!")
    return
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    这里主要利用通道可以在协程之间通信的特点,当调用成功后,向done通道发送信号。
    监听Done信号,如果在time.After超时时间之前接收到,则正常返回,否则走向time.After的超时逻辑,执行超时逻辑代码。
    这里使用的是通道和time.After组合,也可以使用通道和time.NewTimer组合。

    剩下的盛夏~
    关注

    1


    2


    0

    ————————————————
    版权声明:本文为CSDN博主「剩下的盛夏~」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/weixin_44879611/article/details/115537192

  • 相关阅读:
    [原创] 毕设---在myeclipes中安装Hadoop开发插件
    [转]Linux下RPM软件包的安装及卸载 yum操作
    [转]结构化、半结构化和非结构化数据
    [转]这5种必知的大数据处理框架技术
    [转]浅谈Hive vs. HBase 区别在哪里
    前端资源整理
    每个程序员都应该知道的10大基础算法
    Python Day14(HTML)
    Python Day13(yaml)
    Python Day12(补充)
  • 原文地址:https://www.cnblogs.com/ExMan/p/16779145.html
Copyright © 2020-2023  润新知