go某函数执行超时触发器

anko · 2019-12-26 16:58:40 · 3122 次点击 · 预计阅读时间 2 分钟 · 大约8小时之前 开始浏览    
这是一个创建于 2019-12-26 16:58:40 的文章,其中的信息可能已经有所发展或是发生改变。

在群里讨论怎么限制某函数的执行时间,想了很久,终于找到非常简洁的写法(手动捂脸,很快被打脸),之所以在这里发表,是因为我见过太多新手写不是很好! 也许是许久没发文章,就闲来蛋疼发篇文章,但是这篇文章并不是讲如何限制函数的执行时间,因为函数一旦执行则无法中断,所以不存在这种情况,那么下面讨论的则是:某某函数执行超时后的触发器(注意不是函数开始执行超时)

废话不多说,直接呈上2种我个人认为比较好的写法

(1)第1种是我目前能想到比较好且耗时时间很稳定的写法,但是不易懂且稍微多点内存,代码如下:

package main

import (
    "fmt"
    "time"
)
var start time.Time
var end time.Time
func main() {
    test := func() {
        start=time.Now()
        time.Sleep(5e9)
    }
    limitTime1(test, 3e9)//可以将这里的时间改为超过5s
    end=time.Now()
    fmt.Println("test()耗时:",end.Sub(start))
}

func limitTime1(test func(), duration time.Duration) {
    var ch = make(chan bool)
    go func() {
        go func() {
            //先开启计时
            <-time.NewTimer(duration).C
            //如果能执行到这里则说明test()函数超时
            ch<-true
            }()
        //再执行要监控的程序
        test()
        //如果能执行到这里则说明test()函数正常执行完,不超时
        ch <- true
    }()
    //这里阻塞等于模拟了监控计时
    <-ch
}

结果截图如下:

image.png

(2)第2种是我认为不够简洁而且耗时时间由于随机性可能会出现误差比较大(可能2个数量级)的写法,但是易懂点,代码如下:

package main

import (
    "fmt"
    "time"
)
var start time.Time
var end time.Time
func main() {
    test := func() {
        start=time.Now()
        time.Sleep(5e9)
    }
    limitTime(test, 3e9)//可以将这里的时间改为超过5s
    end=time.Now()
    fmt.Println("test()耗时:",end.Sub(start))
}

func limitTime(test func(), duration time.Duration) {
    ch := make(chan bool)
    var t <-chan time.Time
    go func() {
        //开始计时
        t = time.NewTimer(duration).C
        ch <- true
        //运行监控程序
        test()
        ch <- true
    }()
    //阻塞到t被赋值
    <-ch
    //开启监控,在这里会被阻塞
    select {
    case <-t:
    case <-ch:
    }

}

结果截图如下:

image.png

(3)下面放上大佬的写法,简直吊打我上面的2种,写出了go范,我实在惭愧~~~~,大佬的源码是:https://github.com/geektime-geekbang/go_learning/blob/master/code/ch47/optimization_test.go,我改了下大佬的代码如下:

package main

import (
"fmt"
"time"
)

func AsyncService(service func() string) chan string {
    retCh := make(chan string, 1)
    go func() {
        ret := service()
        fmt.Println("service()执行结束.")
        retCh <- ret
        fmt.Println("service()返回值塞进通道.")
    }()
    return retCh
}

func AsyncServiceOut(service func() string,duration time.Duration)  {
    select {
    case ret := <-AsyncService(service):
        fmt.Println("====",ret)
    case <-time.After(duration):
        fmt.Println("time out")
    }
}

func main() {
    service:=func() string {
        time.Sleep( 3e9)
        return "service()的返回值"
    }
    AsyncServiceOut(service,2e9)

    time.Sleep(7e9)
}

结果截图如下:

image.png

下面对这3种进行对比,伤疤来了(注意代码跟上面的不大相同,有更改):

image.png

上面的大图请用新的标签页打开才是最清晰的!

上面的大图3个结果相差不大,结果从左到右分别为:

  • 0.00194871445
  • 0.00194910536
  • 0.00194995740

如果你有更加好的写法,请在留言区回复我,让我学习下!感谢!

欢迎关注我的go library demo项目


有疑问加站长微信联系(非本文作者))

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

3122 次点击  ∙  1 赞  
加入收藏 微博
3 回复  |  直到 2019-12-27 17:54:58
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传