使用golang获取CPU使用率

Seb*_*oli 35 linux go

我的Go程序需要知道所有系统和用户进程的当前cpu使用百分比.

我怎么能得到它?

c9s*_*c9s 29

看看这个包http://github.com/c9s/goprocinfo,goprocinfo包为你做解析的东西.

stat, err := linuxproc.ReadStat("/proc/stat")
if err != nil {
    t.Fatal("stat read fail")
}

for _, s := range stat.CPUStats {
    // s.User
    // s.Nice
    // s.System
    // s.Idle
    // s.IOWait
}
Run Code Online (Sandbox Code Playgroud)

  • 优秀的图书馆,谢谢.它不止于此! (3认同)

小智 24

我有一个类似的问题,从来没有找到轻量级的实现.这是我的解决方案的精简版,可以回答您的具体问题.我/proc/stat像tylerl推荐的那样对文件进行采样.你会注意到我在样本之间等待3秒以匹配top的输出,但是我在1或2秒内也有很好的结果.我在go例程中的循环中运行类似的代码,然后当我从其他go例程中需要它时访问cpu用法.

你也可以解析输出top -n1 | grep -i cpu以获得cpu使用率,但它只在我的linux盒子上采样半秒,并且在重负载时它是关闭的.当我同步它和以下程序时,常规顶部似乎非常接近:

package main

import (
    "fmt"
    "io/ioutil"
    "strconv"
    "strings"
    "time"
)

func getCPUSample() (idle, total uint64) {
    contents, err := ioutil.ReadFile("/proc/stat")
    if err != nil {
        return
    }
    lines := strings.Split(string(contents), "\n")
    for _, line := range(lines) {
        fields := strings.Fields(line)
        if fields[0] == "cpu" {
            numFields := len(fields)
            for i := 1; i < numFields; i++ {
                val, err := strconv.ParseUint(fields[i], 10, 64)
                if err != nil {
                    fmt.Println("Error: ", i, fields[i], err)
                }
                total += val // tally up all the numbers to get total ticks
                if i == 4 {  // idle is the 5th field in the cpu line
                    idle = val
                }
            }
            return
        }
    }
    return
}

func main() {
    idle0, total0 := getCPUSample()
    time.Sleep(3 * time.Second)
    idle1, total1 := getCPUSample()

    idleTicks := float64(idle1 - idle0)
    totalTicks := float64(total1 - total0)
    cpuUsage := 100 * (totalTicks - idleTicks) / totalTicks

    fmt.Printf("CPU usage is %f%% [busy: %f, total: %f]\n", cpuUsage, totalTicks-idleTicks, totalTicks)
}
Run Code Online (Sandbox Code Playgroud)

好像我被允许链接到我在bitbucket上写的完整实现; 如果不是,请随意删除.到目前为止它只能在linux上运行:systemstat.go


tyl*_*erl 17

获取CPU使用率的机制取决于操作系统,因为这些数字对于不同的操作系统内核意味着略有不同.

在Linux上,您可以通过读取文件/proc/系统中的伪文件来查询内核以获取最新的统计信息.当您读取它们以反映机器的当前状态时,它们会即时生成.

具体而言,/proc/<pid>/stat每个进程的文件包含关联的进程记帐信息.它在proc(5)中有记载.你是在专门领域的兴趣utime,stime,cutimecstime(在第14场首发).

您可以轻松地计算百分比:只需读取数字,等待一段时间间隔,然后再次阅读.取差价,除以你等待的时间,这是你的平均值.这正是top程序所做的(以及执行相同服务的所有其他程序).请记住,如果CPU数超过1,则可以使用超过100%的CPU.

如果您只想要一个系统范围的摘要,报告的内容/proc/stat- 使用相同的技术计算您的平均值,但您只需要读取一个文件.


Den*_*ret 14

您可以使用该os.exec包执行ps命令并获取结果.

这是一个发出ps aux命令的程序,解析结果并在linux上打印所有进程的CPU使用情况:

package main

import (
    "bytes"
    "log"
    "os/exec"
    "strconv"
    "strings"
)

type Process struct {
    pid int
    cpu float64
}

func main() {
    cmd := exec.Command("ps", "aux")
    var out bytes.Buffer
    cmd.Stdout = &out
    err := cmd.Run()
    if err != nil {
        log.Fatal(err)
    }
    processes := make([]*Process, 0)
    for {
        line, err := out.ReadString('\n')
        if err!=nil {
            break;
        }
        tokens := strings.Split(line, " ")
        ft := make([]string, 0)
        for _, t := range(tokens) {
            if t!="" && t!="\t" {
                ft = append(ft, t)
            }
        }
        log.Println(len(ft), ft)
        pid, err := strconv.Atoi(ft[1])
        if err!=nil {
            continue
        }
        cpu, err := strconv.ParseFloat(ft[2], 64)
        if err!=nil {
            log.Fatal(err)
        }
        processes = append(processes, &Process{pid, cpu})
    }
    for _, p := range(processes) {
        log.Println("Process ", p.pid, " takes ", p.cpu, " % of the CPU")
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 从命令输出中解析字符串并不是一个很好的解决方案,因为命令可能会发生变化,而且对 cpu/mem/等的占用也很大。 (2认同)

Kyl*_*per 6

这是一个使用Cgo来利用C标准库提供的clock()函数的独立于操作系统的解决方案:

//#include <time.h>
import "C"
import "time"

var startTime = time.Now()
var startTicks = C.clock()

func CpuUsagePercent() float64 {
    clockSeconds := float64(C.clock()-startTicks) / float64(C.CLOCKS_PER_SEC)
    realSeconds := time.Since(startTime).Seconds()
    return clockSeconds / realSeconds * 100
}
Run Code Online (Sandbox Code Playgroud)

  • 您可以将 `time.Now().Sub(startTime)` 简化为 `time.Since(startTime)`。 (2认同)