我正在尝试测量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
}
答案 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
}
}
}