如何在Python 2.7中获取CPU使用率,而不使用PSUtil?

5
尝试在不使用PSUtil的情况下获取Python中的CPU使用率。我尝试了以下方法,但它似乎总是报告相同的数字…
def getCPUuse():
    return(str(os.popen("top -n1 | awk '/Cpu\(s\):/ {print $2}'").readline().strip(\
)))

print(getCPUuse())

即使我使用CPU,这似乎总是报告3.7%。

我也尝试了以下方法...

str(round(float(os.popen('''grep 'cpu ' /proc/stat | awk '{usage=($2+$4)*100/($2+$4+$5)} END {print usage }' ''').readline()),2))

这似乎总是返回5.12。承认我不太清楚上面的代码是做什么的。如果我在命令行中输入grep cpu /proc/stat,我会得到类似于以下内容...

cpu  74429 1 19596 1704779 5567 0 284 0 0 0
cpu0 19596 0 4965 422508 1640 0 279 0 0 0
cpu1 18564 1 4793 427115 1420 0 1 0 0 0
cpu2 19020 0 4861 426916 1206 0 2 0 0 0
cpu3 17249 0 4977 428240 1301 0 2 0 0 0

我猜测我的命令没有正确地从上面的输出中提取所有CPU核心的值?
我的目标是在不使用PSUtil的情况下获取设备(Raspberry PI)的总CPU%。该数字应反映操作系统任务管理器中显示的内容。
2个回答

9
PSUtil、htop、mpstat 等工具所做的事情是从 /proc/stat 文件中读取以 "cpu" 开头(实际上是第一行)的行,然后根据该行中的值计算百分比。您可以在 man 5 proc 中查找这些值的含义(搜索 "proc/stat")。这也是您提到的 grep cpu /proc/stat | awk .... 命令所做的事情。但是,/proc/stat 中的值表示自上次启动以来花费的时间!它们可能在一段时间后重新开始计数,我不确定,但关键是这些数字是长时间测量的。因此,如果您运行该命令,并在几秒钟(分钟甚至小时)后再次运行,它们不会有太大变化!这就是为什么您看到它总是返回 5.12 的原因。像 top 这样的程序记住先前的值并将其从新读取的值中减去。从结果中可以计算出一个“实时”百分比,真正反映了最近的 CPU 负载。为了尽可能简单地在 Python 中完成这样的操作,但又不使用外部命令读取 /proc/stat 并为我们执行计算,我们可以将读取的值存储到文件中。下一次运行时,我们可以将其读回,并从新值中减去它们。
#!/usr/bin/env python2.7

import os.path

# Read first line from /proc/stat. It should start with "cpu"
# and contains times spent in various modes by all CPU's totalled.
#
with open("/proc/stat") as procfile:
    cpustats = procfile.readline().split()

# Sanity check
#
if cpustats[0] != 'cpu':
    raise ValueError("First line of /proc/stat not recognised")

#
# Refer to "man 5 proc" (search for /proc/stat) for information
# about which field means what.
#
# Here we do calculation as simple as possible:
# CPU% = 100 * time_doing_things / (time_doing_things + time_doing_nothing)
#

user_time = int(cpustats[1])    # time spent in user space
nice_time = int(cpustats[2])    # 'nice' time spent in user space
system_time = int(cpustats[3])  # time spent in kernel space

idle_time = int(cpustats[4])    # time spent idly
iowait_time = int(cpustats[5])    # time spent waiting is also doing nothing

time_doing_things = user_time + nice_time + system_time
time_doing_nothing = idle_time + iowait_time

# The times read from /proc/stat are total times, i.e. *all* times spent
# doing things and doing nothing since last boot.
#
# So to calculate  meaningful CPU % we need to know how much these values
# have *changed*.  So we store them in a file which we read next time the
# script is run.
# 
previous_values_file = "/tmp/prev.cpu"
prev_time_doing_things = 0
prev_time_doing_nothing = 0

try:
    with open(previous_values_file) as prev_file:
        prev1, prev2 = prev_file.readline().split()
    prev_time_doing_things = int(prev1)
    prev_time_doing_nothing = int(prev2)
except IOError:  # To prevent error/exception if file does not exist. We don't care.
    pass   

# Write the new values to the file to use next run
#
with open(previous_values_file, 'w') as prev_file:
    prev_file.write("{} {}\n".format(time_doing_things, time_doing_nothing))

# Calculate difference, i.e: how much the number have changed
#
diff_time_doing_things = time_doing_things - prev_time_doing_things
diff_time_doing_nothing = time_doing_nothing - prev_time_doing_nothing

# Calculate a percentage of change since last run:
#
cpu_percentage = 100.0 * diff_time_doing_things/ (diff_time_doing_things + diff_time_doing_nothing)

# Finally, output the result
#
print "CPU", cpu_percentage, "%"

这是一份类似于 top 的版本,每秒钟打印 CPU 使用率,并将前一次测量的 CPU 时间记录在变量中,而不是文件中。
#!/usr/bin/env python2.7

import os.path
import time

def get_cpu_times():
    # Read first line from /proc/stat. It should start with "cpu"
    # and contains times spend in various modes by all CPU's totalled.
    #
    with open("/proc/stat") as procfile:
        cpustats = procfile.readline().split()

    # Sanity check
    #
    if cpustats[0] != 'cpu':
        raise ValueError("First line of /proc/stat not recognised")

    # Refer to "man 5 proc" (search for /proc/stat) for information
    # about which field means what.
    #
    # Here we do calculation as simple as possible:
    #
    # CPU% = 100 * time-doing-things / (time_doing_things + time_doing_nothing)
    #

    user_time = int(cpustats[1])    # time spent in user space
    nice_time = int(cpustats[2])    # 'nice' time spent in user space
    system_time = int(cpustats[3])  # time spent in kernel space

    idle_time = int(cpustats[4])    # time spent idly
    iowait_time = int(cpustats[5])    # time spent waiting is also doing nothing

    time_doing_things = user_time + nice_time + system_time
    time_doing_nothing = idle_time + iowait_time

    return time_doing_things, time_doing_nothing


def cpu_percentage_loop():
    prev_time_doing_things = 0
    prev_time_doing_nothing = 0
    while True:  # loop forever printing CPU usage percentage
        time_doing_things, time_doing_nothing = get_cpu_times()
        diff_time_doing_things = time_doing_things - prev_time_doing_things
        diff_time_doing_nothing = time_doing_nothing - prev_time_doing_nothing
        cpu_percentage = 100.0 * diff_time_doing_things/ (diff_time_doing_things + diff_time_doing_nothing)

        # remember current values to subtract next iteration of the loop
        #
        prev_time_doing_things = time_doing_things
        prev_time_doing_nothing = time_doing_nothing

        # Output latest perccentage
        #
        print "CPU", cpu_percentage, "%"

        # Loop delay
        #
        time.sleep(1)

if __name__ == "__main__":
    cpu_percentage_loop()

有趣的解决方案。你认为每个样本之间需要多少时间?我在想是否可以将当前值保存在内存中,以避免写入文件,并在比较之前休眠指定的时间。 - Remotec
当然,这就是 top 和 htop 的作用:它们(默认情况下)每秒刷新一次,并将前一秒钟的 CPU 时间花费保留在内存中。 - Hkoof
"man 5 proc" 表示时间以“大多数架构的1/100秒”为单位进行测量。因此,只有当您开始使用短于0.1秒的时间时,它们才开始变得不太有意义。 - Hkoof
1
添加了一个版本的Python脚本,它不会写入文件,而是将先前的测量结果存储在变量中。 - Hkoof
太棒了,加一!我不知道为什么这没有得到足够的赞! - Yahya

1
那并不是很容易,因为您描述的大多数进程提供了CPU使用率的累积或总平均值。也许您可以尝试使用随同“systat”软件包一起提供的“mpstat”命令。因此,我用以下步骤编写了以下脚本:1. 要求“mpstat”生成2个报告,一个是现在,另一个是1秒后(“mpstat 1 2”);2. 然后我们得到“Average”行(最后一行);3. 最后一列是“%idle”列,所以我们使用awk中的$NF变量来获取它;4. 我们使用subprocess中的Popen,但设置shell=True来接受我们的管道选项(|);5. 我们执行命令(communicate());6. 使用strip清除输出;7. 并从100中减去它(空闲百分比),以便我们可以获得已用值。

由于它会休眠1秒钟,所以不要担心它不是一个即时命令。

import subprocess                                      

cmd = "mpstat 1 2 | grep Average | awk '{print $NF}'"
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)                                   
out, err = p.communicate()                   
idle = float(out.strip())                              
print(100-idle) 

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接