Golang Go语言中如何检测协程的连续执行时间?

发布于 1周前 作者 nodeper 来自 Go语言

Golang Go语言中如何检测协程的连续执行时间?

嗯,推断说,某个协程连续执行了大段的时间,导致服务端卡住(其他协成无法得到 CPU 时间)

现在的问题是要怎么找出这个协成,即如何获取某个携程的连续执行时间(不是测量函数执行时间,而是协程连续运行,不让渡 CPU 的持续时间)

8 回复

协程的三种写法。。

更多关于Golang Go语言中如何检测协程的连续执行时间?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


难道不是改代码?
死循环是会触发调度器 bug 的

协程调度的问题可能性不大吧,生成火焰图看一下。工具很多,可以参考: https://github.com/uber/go-torch

#4 cpu 火焰图,是 cpu 累计时间吧。。。查 latency 应该不是查这个吧?

不知道楼主问题解决没有?我不知道楼主得到这个推断的理由是什么,我的想法是这样子的,你说服务端卡住,猜测是某个协程连续执行了大段时间,这里是两个要素,一个大段时间,二是连续执行。如果是连续执行,那么本质上是怀疑 go 的协程调度出现了一些问题, 说实话,这个结果我是不敢相信的。另一个要素是大段时间,这个可以通过火焰图看出来。我没有用过 go tool trace,没办法给出针对性意见。我不知道楼主更具体的情况,所以没有办法肯定一定是 cpu 卡,而不是 io 或是别的什么卡,我的方法可能还是利用 go tool pprof,可以着重看其中的两个指标 block 和 profile, 如果真是 cpu 的问题,profile 指标和火焰图应该能够分析出来。

#6 嗯,谢谢, 应该是 block 问题

50 多个连接, 负载不是很大, 占了 15%~20% 的 CPU

查了下, profile,
970ms 21.85% 21.85% 970ms 21.85% runtime.futex

[futex 好像是 linux 的用户空间的快速锁]( https://zh.wikipedia.org/wiki/Futex)

应该是 cas 的模式吧…然后怀疑 futex 是 spinlock, 接着查询到 [futex 是支持 futex_wait 和 futex_wake 就是支持唤醒机制]( http://blog.sina.com.cn/s/blog_e59371cc0102v29b.html)

既然 futex 支持唤醒机制,为什么会这么耗 CPU, 在锁上耗 CPU,不是因为不断的尝试获取锁吗?

(pprof) tree
Showing nodes accounting for 3.53s, 79.50% of 4.44s total
Dropped 281 nodes (cum <= 0.02s)
Showing top 80 nodes out of 240
----------------------------------------------------------±------------
flat flat% sum% cum cum% calls calls% + context
----------------------------------------------------------±------------
0.41s 42.27% | runtime.futexsleep
0.31s 31.96% | runtime.systemstack
0.24s 24.74% | runtime.startm
0.01s 1.03% | runtime.unlock
0.97s 21.85% 21.85% 0.97s 21.85% | runtime.futex
----------------------------------------------------------±------------
0.24s 55.81% | syscall.Write
0.19s 44.19% | internal/poll.(*FD).Read
0.33s 7.43% 29.28% 0.43s 9.68% | syscall.Syscall
0.09s 20.93% | runtime.reentersyscall
0.01s 2.33% | runtime.exitsyscall

在Golang(Go语言)中,要检测协程(goroutine)的连续执行时间,你可以使用标准库中的 time 包来实现。以下是一个基本的方法,通过记录协程开始和结束的时间来计算其执行时间:

  1. 导入 time

    import "time"
  2. 记录开始时间: 在协程开始时,记录当前的时间。

    startTime := time.Now()
  3. 执行你的逻辑: 放置你需要测量的代码块。

    // 你的代码逻辑
  4. 记录结束时间并计算耗时: 在协程结束时,再次记录当前时间,并计算执行时间。

    endTime := time.Now()
    duration := endTime.Sub(startTime)
    fmt.Printf("协程执行时间: %v\n", duration)

示例完整代码:

package main

import (
    "fmt"
    "time"
)

func main() {
    go func() {
        startTime := time.Now()
        // 模拟工作负载
        time.Sleep(2 * time.Second)
        endTime := time.Now()
        duration := endTime.Sub(startTime)
        fmt.Printf("协程执行时间: %v\n", duration)
    }()
    // 确保主协程等待其他协程完成(在实际应用中,可能需要更复杂的同步机制)
    time.Sleep(3 * time.Second)
}

注意:上述示例使用了 time.Sleep 来模拟工作负载,并且简单地通过 time.Sleep 确保主协程等待子协程完成。在实际应用中,应使用更合适的同步机制,如 sync.WaitGroup

回到顶部
AI 助手
你好,我是IT营的 AI 助手
您可以尝试点击下方的快捷入口开启体验!