6

我知道[1]。通过几行代码,我只想从CPU使用率最高的前n个进程中提取当前的CPU使用率。或多或少的前 5 行top。使用github.com/shirou/gopsutil/process这很简单:

// file: gotop.go
package main

import (
  "log"
  "time"
  "sort"

  "github.com/shirou/gopsutil/process"
)


type ProcInfo struct{
  Name  string
  Usage float64
} 

type ByUsage []ProcInfo

func (a ByUsage) Len() int      { return len(a) }
func (a ByUsage) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a ByUsage) Less(i, j int) bool {
  return a[i].Usage > a[j].Usage
}


func main() {

  for {
    processes, _ := process.Processes()

    var procinfos []ProcInfo
    for _, p := range processes{
      a, _ := p.CPUPercent()
      n, _ := p.Name()
      procinfos = append(procinfos, ProcInfo{n, a})
    }
    sort.Sort(ByUsage(procinfos))

    for _, p := range procinfos[:5]{
      log.Printf("   %s -> %f", p.Name, p.Usage)
    }
    time.Sleep(3 * time.Second)
  }
}

虽然这个实现gotop的刷新率和top一样是 3 秒,但gotop大约有 3 秒。像top一样获得这些值对 CPU 使用率的要求高出 5 倍。有什么技巧可以更有效地读取 5 个最消耗量的进程吗?我还试图找到top的实现,看看它是如何在那里实现的。

psutils是造成这种减速的原因吗?我发现在 GO 中也实现了cpustat 。但甚至sudo ./cpustat -i 3000 -s 1似乎不如top.

主要动机是通过相当少量的计算工作来监控当前机器的使用情况,以便它可以在后台作为服务运行。

看来,甚至htop只是在阅读 /proc/stat

此处的评论中建议的编辑是分析时的结果

Showing top 10 nodes out of 46 (cum >= 70ms)
      flat  flat%   sum%        cum   cum%
      40ms 40.00% 40.00%       40ms 40.00%  syscall.Syscall
      10ms 10.00% 50.00%       30ms 30.00%  github.com/shirou/gopsutil/process.(*Process).fillFromStatusWithContext
      10ms 10.00% 60.00%       30ms 30.00%  io/ioutil.ReadFile
      10ms 10.00% 70.00%       10ms 10.00%  runtime.slicebytetostring
      10ms 10.00% 80.00%       20ms 20.00%  strings.FieldsFunc
      10ms 10.00% 90.00%       10ms 10.00%  syscall.Syscall6
      10ms 10.00%   100%       10ms 10.00%  unicode.IsSpace
         0     0%   100%       10ms 10.00%  bytes.(*Buffer).ReadFrom
         0     0%   100%       70ms 70.00%  github.com/shirou/gopsutil/process.(*Process).CPUPercent
         0     0%   100%       70ms 70.00%  github.com/shirou/gopsutil/process.(*Process).CPUPercentWithContext

似乎系统调用需要永远。树转储在这里: https ://gist.github.com/PatWie/4fa528b7d7b1d0b5c1b665c056671477

这将问题变为: - 系统调用是问题吗?- 该程序是否有任何 c 源top?我刚刚找到了 htop 的实现 - 有一个简单的解决方法吗?我考虑用c写它,然后把它包装起来。

4

1 回答 1

0

github.com/shirou/gopsutil/process使用ioutil.ReadFile访问文件系统的效率低于顶部。特别是ReadFile

  • 调用Stat增加了一个额外的不必要的系统调用。
  • 使用os.Open而不是unix.Openat+ ,这会在解析路径时os.NewFile导致额外的内核时间遍历。仍然有点低效,因为它总是检查文件描述符是否是非阻塞的。这可以通过直接使用or包来避免。/procos.NewFilegolang.org/x/sys/unixsyscall

在 Linux 下检索进程详细信息通常效率很低(大量文件系统扫描、编组文本数据)。top但是,您可以通过修复文件系统访问(如上所述)来获得与 Go 类似的性能。

于 2021-09-23T14:25:06.767 回答