如何正确计算Go语言Goroutine并发函数的执行时间?
关于Goroutine并发函数执行时间的正确计算方法
首先纠正你的理解误区:你当前代码计算的是函数从启动到结束的墙钟时间(实际流逝的时间),这个结果是准确的。Goroutine的调度切换确实会让它交替执行,但墙钟时间统计的是整个函数生命周期的真实耗时——不管中间被调度出去多少次,从time.Now()到time.Since(start)的时间就是函数从开始到完成的实际时间,这符合大多数场景下的“执行时间”需求。
你的现有代码存在语法错误,修正后可以正常使用:
import ( "fmt" "time" ) func timeElapsed() func() { start := time.Now() return func() { elapsed := time.Since(start) fmt.Println("函数执行耗时:", elapsed) } } func thisIsGoFunction() { // 补全(),修正语法错误 defer timeElapsed()() // 你的业务代码:遍历map、使用mutex等逻辑 }
如果你需要统计的是该Goroutine实际占用CPU的时间(排除调度等待、IO等待等非CPU耗时),则需要借助系统调用或Go runtime的指标来实现。以下是基于syscall获取线程CPU时间的示例(需绑定Goroutine到线程):
import ( "fmt" "runtime" "syscall" "time" ) func getCPUTime() (user, sys time.Duration, err error) { var rusage syscall.Rusage if err := syscall.Getrusage(syscall.RUSAGE_SELF, &rusage); err != nil { return 0, 0, err } user = time.Duration(rusage.Utime.Nano()) sys = time.Duration(rusage.Stime.Nano()) return user, sys, nil } func timeCPUEapsed() func() { startUser, startSys, _ := getCPUTime() return func() { endUser, endSys, _ := getCPUTime() userElapsed := endUser - startUser sysElapsed := endSys - startSys fmt.Printf("用户态CPU耗时: %v, 内核态CPU耗时: %v, 总CPU耗时: %v\n", userElapsed, sysElapsed, userElapsed+sysElapsed) } } func thisIsGoFunction() { // 绑定Goroutine到当前线程,确保统计的是该Goroutine的CPU时间 runtime.LockOSThread() defer runtime.UnlockOSThread() defer timeCPUEapsed()() // 你的业务代码:遍历map、使用mutex等逻辑 }
- 绑定线程(
runtime.LockOSThread())会阻止Go runtime调度该线程上的其他Goroutine,仅在需要精确统计单个Goroutine的CPU时间时使用,不推荐在高并发场景下滥用。 - 如果是统计多个Goroutine的总CPU耗时,更适合用
pprof工具进行性能分析,而非在代码中硬编码统计。
内容的提问来源于stack exchange,提问作者Atharva Ajgaonkar
相关产品推荐
相关产品推荐

