【问题标题】:Is there an efficient way to calculate execution time in golang?有没有一种有效的方法来计算 golang 中的执行时间?
【发布时间】:2018-01-27 17:25:25
【问题描述】:

我正在寻找在 go 中计算执行时间的最佳方法。

func main() {
    start := time.Now()

    time.Sleep(time.Second * 2)

    //something doing here

    elapsed := time.Since(start)
    fmt.Printf("page took %s", elapsed)
}

上面的代码运行良好。

但是当我使用模板时,我必须为每个模板功能重新编写。

是否有一种高效计算执行时间的方法,包括模板?

【问题讨论】:

标签: go execution-time


【解决方案1】:

如果你正在对整个函数进行计时,那么你可以使用defer 来消除一些重复的代码。

func elapsed(what string) func() {
    start := time.Now()
    return func() {
        fmt.Printf("%s took %v\n", what, time.Since(start))
    }
}

func main() {
    defer elapsed("page")()  // <-- The trailing () is the deferred call
    time.Sleep(time.Second * 2)
}

playground example

specification says this about deferred calls:

每次执行“defer”语句时,调用的函数值和参数都会照常计算并重新保存,但不会调用实际函数。而是在周围函数返回之前立即调用延迟函数,

函数值elapsed("page") 在 defer 语句中求值。 elapsed 函数记录当前时间并返回一个匿名函数。返回的匿名函数在周围函数返回之前立即调用。匿名函数计算并打印经过的时间。

【讨论】:

  • 延迟调用的参数被立即评估,但是直到周围的函数返回时才执行函数调用。例如defer outcall(incall())incall() 立即计算,而outcall() 直到周围的函数返回才执行。
【解决方案2】:

Cerise提供的解决方案非常完美。


另外,如果你不想显式传递函数名,你可以这样完成:

func SomeFunction(list *[]string) {
    defer TimeTrack(time.Now())
    // Do whatever you want.
}

func TimeTrack(start time.Time) {
    elapsed := time.Since(start)

    // Skip this function, and fetch the PC and file for its parent.
    pc, _, _, _ := runtime.Caller(1)

    // Retrieve a function object this functions parent.
    funcObj := runtime.FuncForPC(pc)

    // Regex to extract just the function name (and not the module path).
    runtimeFunc := regexp.MustCompile(`^.*\.(.*)$`)
    name := runtimeFunc.ReplaceAllString(funcObj.Name(), "$1")

    log.Println(fmt.Sprintf("%s took %s", name, elapsed))
}

因此,您会得到:

SomeFunction took 15.483µs


更多信息,请参考这篇文章:Go Function Tracing

分享知识。 :)

【讨论】:

    【解决方案3】:

    使用初始化函数

    package main
    
    import (
        "fmt"
        "time"
    )
    
    var start time.Time
    
    func init() {
        start = time.Now()
    }
    
    func getChars(s string) {
        for _, c := range s {
            fmt.Printf("%c at time %v\n", c, time.Since(start))
            time.Sleep(10 * time.Millisecond)
        }
    }
    
    func main() {
        fmt.Println("main execution started at time", time.Since(start))
    
        getChars("Hello")
    
        fmt.Println("\nmain execution stopped at time", time.Since(start))
    }
    

    【讨论】:

      【解决方案4】:

      在 golang 中计算执行时间的有效方法

      您可以使用延迟函数在控制台上轻松获取执行时间

      即使代码出错,延迟函数也会执行,因此您始终可以获得执行时间。

      时间包用于获取时差。

      func main() {
          now := time.Now()
          defer func() {
              fmt.Println(time.Now().Sub(now))
          }()
              
          // Here you can do whatever you want
      }
      

      或者你可以使用这个代码

      func main() {
              now := time.Now()
              defer func() {
                  fmt.Println(time.Since(now))
              }()
                  
              // Here you can do whatever you want
          }
      

      查看Playground 中的代码以获取更多信息。我添加了一些功能来从错误中恢复,同时打印执行时间,即使在出现紧急错误的情况下也是如此。

      【讨论】:

      • 在封闭函数结束之前推迟事实(即在您想要计时的代码之后)并不是真的有用,因为这样您就可以直接执行第二次计时和打印,而无需defer 并具有完全相同的功能。 defer 的存在是为了在相关代码之前安排一些调用(在之后执行),并且无论在相关代码期间发生恐慌或早期救助,都会被调用。
      • 基于问题 defer 很有用。即使出现恐慌,它也会起作用。
      • 我并不怀疑defer 通常对计时很有用(其他答案显示了使用它的好方法)。只是它在 this 答案中的使用方式并不是很有成效。特别是在函数末尾放置defer 是没有意义的。
      • @blubberdiblub 是的,但是 defer 可以放在你想要的代码的任何位置。它将被添加到延迟堆栈中,并将执行延迟函数的任何位置。所以我认为它更有用,因为我们可以懒惰地编码......
      • 这个答案与两年前发布的accepted one 没有什么不同。有什么意义?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-06-05
      • 1970-01-01
      相关资源
      最近更新 更多