在golang中,有一种高效的方法可以计算执行时间吗?

huangapple go评论100阅读模式
英文:

Is there an efficient way to calculate execution time in golang?

问题

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

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

    time.Sleep(time.Second * 2)

    // 在这里进行一些操作

    elapsed := time.Since(start)
    fmt.Printf("页面加载时间:%s", elapsed)
}

上面的代码可以正常工作。

但是当我使用模板时,我必须为每个模板函数重新编写代码。

有没有一种高效的方法来计算执行时间,包括使用模板的情况?

英文:

I'm looking for the best way to calculate execution time in go.

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

    time.Sleep(time.Second * 2)

    //something doing here

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

The code above works fine.

But when I use templates, I have to write it again for each template function.

Is there an efficient way of calculating execution time, including with templates?

答案1

得分: 126

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

// timer返回一个函数,该函数打印name参数和从调用timer到调用返回的函数之间的经过时间。返回的函数用于defer语句中:
//
//   defer timer("sum")()
func timer(name string) func() {
    start := time.Now()
    return func() {
        fmt.Printf("%s took %v\n", name, time.Since(start))
    }
}

func main() {
    defer timer("main")()  // <-- 后面的()是延迟调用
    time.Sleep(time.Second * 2)
}   // 输出: main took 2s

playground上运行示例

规范对延迟调用有如下说明

每次执行"defer"语句时,函数值和调用的参数都会像平常一样被求值并重新保存,但实际的函数不会被调用。相反,延迟函数会在包围它的函数返回之前立即被调用。

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


使用runtime.Callersruntime.CallersFrames可以自动获取调用函数的名称。

// callerName返回跳过调用堆栈中的skip帧的函数名称。
func callerName(skip int) string {
    const unknown = "unknown"
    pcs := make([]uintptr, 1)
    n := runtime.Callers(skip+2, pcs)
    if n < 1 {
        return unknown
    }
    frame, _ := runtime.CallersFrames(pcs).Next()
    if frame.Function == "" {
        return unknown
    }
    return frame.Function
}

// timer返回一个函数,该函数打印调用函数的名称和从调用timer到调用返回的函数之间的经过时间。返回的函数用于defer语句中:
//
//   defer timer()()
func timer() func() {
    name := callerName(1)
    start := time.Now()
    return func() {
        fmt.Printf("%s took %v\n", name, time.Since(start))
    }
}

func main() {
    defer timer()()
    time.Sleep(time.Second * 2)
}   // 输出: main.main took 2s

请注意,与本答案的前半部分使用字符串字面量相比,获取函数名称会有运行时成本。为了避免测量获取函数名称的成本,timer在记录开始时间之前获取名称。

playground上运行示例

英文:

If you are timing an entire function, then you can use defer to eliminate some of the repetitive code.

// timer returns a function that prints the name argument and 
// the elapsed time between the call to timer and the call to
// the returned function. The returned function is intended to
// be used in a defer statement:
//
//   defer timer(&quot;sum&quot;)()
func timer(name string) func() {
	start := time.Now()
	return func() {
		fmt.Printf(&quot;%s took %v\n&quot;, name, time.Since(start))
	}
}

func main() {
	defer timer(&quot;main&quot;)()  // &lt;-- The trailing () is the deferred call
	time.Sleep(time.Second * 2)
}   // prints: main took 2s

Run the example on the playground.

The specification says this about deferred calls:

> Each time a "defer" statement executes, the function value and parameters to the call are evaluated as usual and saved anew but the actual function is not invoked. Instead, deferred functions are invoked immediately before the surrounding function returns,

The function value timer(&quot;main&quot;) is evaluated at the defer statement. The timer function records the current time and returns an anonymous function. The returned anonymous function is invoked immediately before the surrounding function returns. The anonymous function computes and prints the elapsed time.


Use runtime.Callers and runtime.CallersFrames to automatically get the name of the calling function.

// callerName returns the name of the function skip frames up the call stack.
func callerName(skip int) string {
	const unknown = &quot;unknown&quot;
	pcs := make([]uintptr, 1)
	n := runtime.Callers(skip+2, pcs)
	if n &lt; 1 {
		return unknown
	}
	frame, _ := runtime.CallersFrames(pcs).Next()
	if frame.Function == &quot;&quot; {
		return unknown
	}
	return frame.Function
}

// timer returns a function that prints the name of the calling
// function and the elapsed time between the call to timer and
// the call to the returned function. The returned function is
// intended to be used in a defer statement:
//
//   defer timer()()
func timer() func() {
    name := callerName(1)
	start := time.Now()
	return func() {
		fmt.Printf(&quot;%s took %v\n&quot;, name, time.Since(start))
	}
}

func main() {
	defer timer()()
	time.Sleep(time.Second * 2)
}   // prints: main.main took 2s

Note that there is a runtime cost for getting the function name compared to using a string literal as in the first part of this answer. To avoid measuring the cost of getting the function name, timer gets the name before recording the start time.

Run the example on the playground.

答案2

得分: 27

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

此外,如果你不想显式传递函数名,你可以这样实现:

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

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

    // 跳过此函数,获取其父函数的PC和文件。
    pc, _, _, _ := runtime.Caller(1)

    // 检索此函数父函数的函数对象。
    funcObj := runtime.FuncForPC(pc)

    // 用于提取函数名(而不是模块路径)的正则表达式。
    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

分享知识。 在golang中,有一种高效的方法可以计算执行时间吗?

英文:

The solution provided by Cerise Limón is perfect.


In addition, if you don't want to pass function name explicitly, you could accomplish it like this:

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(), &quot;$1&quot;)

	log.Println(fmt.Sprintf(&quot;%s took %s&quot;, name, elapsed))
}

As a result, you would get:
> SomeFunction took 15.483&#181;s


For more information, Refer this article: Go Function Tracing

Share the knowledge. 在golang中,有一种高效的方法可以计算执行时间吗?

答案3

得分: 4

使用init函数

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 在时间 %v\n", c, time.Since(start))
        time.Sleep(10 * time.Millisecond)
    }
}

func main() {
    fmt.Println("主程序开始执行的时间", time.Since(start))

    getChars("Hello")

    fmt.Println("\n主程序停止执行的时间", time.Since(start))
}
英文:

Use init function

package main

import (
	&quot;fmt&quot;
	&quot;time&quot;
)

var start time.Time

func init() {
	start = time.Now()
}

func getChars(s string) {
	for _, c := range s {
		fmt.Printf(&quot;%c at time %v\n&quot;, c, time.Since(start))
		time.Sleep(10 * time.Millisecond)
	}
}

func main() {
	fmt.Println(&quot;main execution started at time&quot;, time.Since(start))

	getChars(&quot;Hello&quot;)

	fmt.Println(&quot;\nmain execution stopped at time&quot;, time.Since(start))
}

答案4

得分: 2

在Go语言中,计算执行时间的高效方法如下:

你可以使用defer函数在控制台上轻松获取执行时间

defer函数即使在代码出现错误时也会执行,因此你总是可以得到执行时间。

使用time包来获取时间差异。

func main() {
    now := time.Now()
    defer func() {
        fmt.Println(time.Now().Sub(now))
    }()
        
    // 在这里你可以做任何你想做的事情
}

或者你可以使用以下代码:

func main() {
    now := time.Now()
    defer func() {
        fmt.Println(time.Since(now))
    }()
        
    // 在这里你可以做任何你想做的事情
}

Playground中查看代码以获取更多信息。我添加了一些功能,可以在出现错误时恢复并打印执行时间,即使是在发生panic错误的情况下也可以。

英文:

Efficient way to calculate execution time in golang

You can easily get the execution time on your console using a defer function

> defer functions execute even if the code get an error so you always get the execution time.
>
> time package is used to get the time difference.

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

Or you can use this code

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

check the code in Playground for more. I added some functionality to recover from an error at the same time print the execution time, even if in the case of a panic error.

答案5

得分: 0

用作Golang中平均计算时间的侧面参考(分别针对10、100、1000个元素)。

  • 访问数组中的元素(1/1/1秒)
  • 二分/字典搜索(1/2/3秒)
  • 简单循环/线性搜索(10/100/1,000秒)
  • 快速排序/归并排序/堆排序/时间排序(10/200/3,000秒)
  • 冒泡排序/插入排序/选择排序(100/10,000/1,000,000秒)
英文:

Use this as a side reference for an average computation time in Golang
(for 10,100,1000 elements accordingly).

  • Accessing an element within an array (1/1/1 sec)
  • Binary/dictionary search (1/2/3 sec)
  • Simple loop/linear search (10/100/1,000 sec)
  • Quick Sort/Merge Sort/Heap Sort/Tim Sort (10/200/3,000 sec)
  • Bubble Sort/Insertion Sort/Selection Sort (100/10,000/1,000,000 sec)

huangapple
  • 本文由 发表于 2017年8月19日 08:34:12
  • 转载请务必保留本文链接:https://go.coder-hub.com/45766572.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定