英文:
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
每次执行"defer"语句时,函数值和调用的参数都会像平常一样被求值并重新保存,但实际的函数不会被调用。相反,延迟函数会在包围它的函数返回之前立即被调用。
函数值timer("main")
在defer语句中被求值。timer
函数记录当前时间并返回一个匿名函数。返回的匿名函数会在包围它的函数返回之前立即被调用。匿名函数计算并打印经过的时间。
使用runtime.Callers和runtime.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
在记录开始时间之前获取名称。
英文:
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("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")() // <-- 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("main")
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 = "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 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("%s took %v\n", 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.
答案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
分享知识。
英文:
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(), "$1")
log.Println(fmt.Sprintf("%s took %s", name, elapsed))
}
As a result, you would get:
> SomeFunction took 15.483µs
For more information, Refer this article: Go Function Tracing
Share the knowledge.
答案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 (
"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
得分: 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)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论