测量执行时间并在golang中停止等待

时间:2015-06-15 15:42:08

标签: go

我正在尝试测量funcWithUnpredictiveExecutionTime函数的执行时间。

func measureTime(expectedMs float64) (ok bool) {
    t1 := time.Now()
    funcWithUnpredictiveExecutionTime()
    t2 := time.Now()
    diff := t2.Sub(t1)

funcWithUnpredictiveExecutionTime比我预期的更快地工作时,测量很好。但是如果它比expectedMs慢,那么在预期的毫秒数后,测量就不会停止。

是否可以在funcWithUnpredictiveExecutionTime工作时间超过expectedMs而不等待funcWithUnpredictiveExecutionTime完成时停止测量时间?

换句话说,measureTime(200)应该以{{1​​}}返回,但结果有好或坏。

我想我应该使用频道然后以某种方式取消等待频道。但是怎么做呢?

完整代码:

200 ms

输出:

package main

import (
    "fmt"
    "math/rand"
    "time"
)

// random number between min and max
func random(min, max int) int {
    rand.Seed(time.Now().Unix())
    return rand.Intn(max-min) + min
}

// sleeps for a random milliseconds amount between 200 and 1000
func funcWithUnpredictiveExecutionTime() {
    millisToSleep := random(200, 1000)
    fmt.Println(fmt.Sprintf("Sleeping for %d milliseconds", millisToSleep))
    time.Sleep(time.Millisecond * time.Duration(millisToSleep))
}

// measures execution time of a function funcWithUnpredictiveExecutionTime
// if expectedMs < actual execution time, it's ok.
// if expectedMs milliseconds passed and funcWithUnpredictiveExecutionTime
// still did not finish execution it should return
// without waiting for funcWithUnpredictiveExecutionTime
func measureTime(expectedMs float64) (ok bool) {
    t1 := time.Now()
    funcWithUnpredictiveExecutionTime()
    t2 := time.Now()
    diff := t2.Sub(t1)
    actualMs := diff.Seconds() * 1000
    ok = actualMs < expectedMs
    fmt.Println(actualMs)
    return
}

// prints results: Ok or too late
func printTimeResults(ok bool) {
    if ok {
        fmt.Println("Ok")
    } else {
        fmt.Println("Too late")
    }
}

func main() {
    printTimeResults(measureTime(200))  // expect it to finish in 200 ms anyway
    printTimeResults(measureTime(1000)) // expect it to finish in 1000 ms anyway
}

Playground

2 个答案:

答案 0 :(得分:4)

除非您将其设计为取消,否则您无法取消goroutine。您可以通过使用通道指示正在计时的功能的完成来短路您的计时功能:

func measureTime(expectedMs float64) (ok bool) {
    done := make(chan struct{})
    t1 := time.Now()

    go func() {
        funcWithUnpredictiveExecutionTime()
        close(done)
    }()

    select {
    case <-done:
        ok = true
    case <-time.After(time.Duration(expectedMs) * time.Millisecond):
    }

    fmt.Println(time.Since(t1))
    return ok

}

答案 1 :(得分:1)

将JimB的例子扩展到我个人跟随异步背景工作者的设计。我会说在大多数情况下,在没有通过中止通道的情况下启动go例程是不可接受的...所有的异步方法都应该接受一个作为参数或者在接收类型上定义一个,这样你就可以实际控制执行。 fyi有图书馆,这里有一个简单的图书馆,我的一位老同事; https://github.com/lytics/squaredance

如果您的程序没有针对每个goroutine的中止路径,您很快就会面临重大的质量问题。此外,对于在goroutine中进行任何繁重任务的应用程序,您可能无法正常停止并启动应用程序。

func measureTime(expectedMs float64) (ok bool) {
    done := make(chan struct{})
    abort := make(chan struct{})
    t1 := time.Now()

    go func() {
        funcWithUnpredictiveExecutionTime(abort)
        close(done)
    }()

    select {
    case <-done:
        ok = true
    case <-time.After(time.Duration(expectedMs) * time.Millisecond):
        // after signals here when the duration is reached so I close abort
        close(abort)
    }

    fmt.Println(time.Since(t1))
    return ok

}


funcWithUnpredictiveExecutionTime(abort) {
     for {
        select {
           // doing work in here
           case abort:
              // except here, we clean up and return
        }
     }
}