Golang中如何测量快速操作的执行时间

Golang中如何测量快速操作的执行时间 你好, 我想测量一个耗时极短的子程序的执行时间。一个简单的例子:

package main

import (
	"fmt"
	"time"
)

func main() {
	timer:= time.Now()
	fmt.Println("Hello, playground")
	fmt.Printf("(Execution time: %s) |", time.Since(timer))
}

但这总是返回 0 秒,然而我需要以某种方式测量它(即需要更高的分辨率)。有什么建议吗?谢谢!

6 回复

是的,我的系统运行的是Windows。我将在Ubuntu上运行它,看看结果如何。也会研究一下基准测试……

更多关于Golang中如何测量快速操作的执行时间的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


我确认在Ubuntu系统上运行该代码会返回微秒级的数值,而不仅仅是零。如果能知道Windows系统是否有修复方法就更好了。

不,据我从谷歌搜索结果的理解,目前对此没有修复方法。即使是高分辨率计时器,每个节拍的精度也不会高于0.5毫秒。

如果这是用于基准测试,请使用基准测试功能:https://golang.org/pkg/testing/#hdr-Benchmarks

如果不是用于基准测试,并且你使用的系统计时器分辨率较低(例如 Windows),我想这个时间足够短,不必担心。slight_smile

对我来说并非如此:

$ go run main.go
Hello, playground
(Execution time: 29.073µs) |
$ go run main.go
Hello, playground
(Execution time: 21.639µs) |
$ go run main.go
Hello, playground
(Execution time: 21.575µs) |
$ go run main.go
Hello, playground
(Execution time: 20.104µs) |
$ go run main.go
Hello, playground
(Execution time: 22.327µs) |

也许你是在一个时钟精度不够的系统上测试的?或者你是在 Go Playground 上测试的,那里的时钟不会前进?

在Go中测量微秒或纳秒级操作的执行时间,需要使用time包的高精度方法。以下是几种解决方案:

1. 使用 time.Since() 配合纳秒精度

package main

import (
    "fmt"
    "time"
)

func main() {
    start := time.Now()
    
    // 快速操作示例
    sum := 0
    for i := 0; i < 1000; i++ {
        sum += i
    }
    
    elapsed := time.Since(start)
    fmt.Printf("执行时间: %v\n", elapsed)
    fmt.Printf("纳秒: %d ns\n", elapsed.Nanoseconds())
    fmt.Printf("微秒: %.3f µs\n", float64(elapsed.Nanoseconds())/1000)
    fmt.Printf("毫秒: %.6f ms\n", float64(elapsed.Nanoseconds())/1000000)
}

2. 使用 time.Now().UnixNano() 直接获取纳秒时间戳

package main

import (
    "fmt"
    "time"
)

func main() {
    start := time.Now().UnixNano()
    
    // 需要测量的快速操作
    _ = make([]byte, 1024)
    
    end := time.Now().UnixNano()
    elapsed := end - start
    
    fmt.Printf("执行时间: %d ns\n", elapsed)
    fmt.Printf("执行时间: %.3f µs\n", float64(elapsed)/1000)
}

3. 多次执行取平均值(针对极短操作)

package main

import (
    "fmt"
    "time"
)

func fastOperation() {
    // 模拟快速操作
    _ = 42 * 42
}

func main() {
    iterations := 1000000
    totalTime := time.Duration(0)
    
    for i := 0; i < iterations; i++ {
        start := time.Now()
        fastOperation()
        totalTime += time.Since(start)
    }
    
    avgTime := totalTime / time.Duration(iterations)
    fmt.Printf("平均执行时间: %v\n", avgTime)
    fmt.Printf("平均执行时间: %d ns\n", avgTime.Nanoseconds())
}

4. 使用 runtime.nanotime() 内部函数(最高精度)

package main

import (
    "fmt"
    "time"
    _ "unsafe"
)

//go:linkname nanotime runtime.nanotime
func nanotime() int64

func main() {
    start := nanotime()
    
    // 需要测量的操作
    var x int64
    for i := 0; i < 100; i++ {
        x += int64(i)
    }
    
    end := nanotime()
    elapsed := end - start
    
    fmt.Printf("执行时间: %d ns\n", elapsed)
    fmt.Printf("执行时间: %.3f µs\n", float64(elapsed)/1000)
    
    // 对比标准方法
    stdStart := time.Now()
    for i := 0; i < 100; i++ {
        x += int64(i)
    }
    stdElapsed := time.Since(stdStart)
    fmt.Printf("标准方法: %v\n", stdElapsed)
}

5. 实际应用示例:测量函数调用开销

package main

import (
    "fmt"
    "time"
)

func measureShortOperation() {
    start := time.Now()
    
    // 需要测量的快速操作
    result := 0
    for i := 0; i < 100; i++ {
        result += i * i
    }
    _ = result // 防止编译器优化
    
    elapsed := time.Since(start)
    
    if elapsed < time.Microsecond {
        fmt.Printf("执行时间: %d ns\n", elapsed.Nanoseconds())
    } else if elapsed < time.Millisecond {
        fmt.Printf("执行时间: %.3f µs\n", float64(elapsed.Nanoseconds())/1000)
    } else {
        fmt.Printf("执行时间: %v\n", elapsed)
    }
}

func main() {
    // 测量多次以减少误差
    for i := 0; i < 5; i++ {
        measureShortOperation()
    }
}

关键点:

  1. time.Since() 返回的是 time.Duration 类型,默认字符串格式可能显示为 0s,但实际有纳秒精度
  2. 使用 .Nanoseconds() 方法获取纳秒数值
  3. 对于极短操作,建议多次执行取平均值
  4. 注意编译器优化可能影响测量结果,可使用 _ = result 防止优化
  5. 在Linux/macOS上,Go的 time.Now() 通常使用 clock_gettime(CLOCK_MONOTONIC, ...),精度可达纳秒级

测量结果显示为0秒是因为默认的字符串格式只显示到秒,实际可以通过上述方法获取更高精度的测量结果。

回到顶部