获取CPU和RAM使用情况的Python脚本

522 阅读8分钟

在这篇文章中,我们开发了一个Python脚本,使用psutil库获得系统的CPU和RAM使用情况。我们对它进行了扩展,以获得每个进程和每个内核的CPU和RAM使用情况。

内容列表

以下是我们将在本文中实现的内容:

  • 介绍python中的psutil 库。
  • 使用psutil ,打印整体的CPU使用率。
  • 使用psutil 打印整体的RAM使用情况。
  • 获取每个单独进程的资源使用情况。
  • 获取每个单独的core 的CPU使用率。

介绍psutil

psutil 是Python中的一个库,允许开发者查看计算机系统的资源使用情况。它提供了许多不同的函数和类,使分析一个系统的资源使用情况的任务更加容易。

安装

要安装psutil 库,我们首先需要python3python3-pip 来安装和使用python包。

窗口

Windows 上安装 python 是相当容易的。Python 的安装可以从**微软商店**获得。如果你想有一个自定义的安装,你可以遵循这个链接。

Linux系统

Linux ,你可以使用其中一个软件包管理器来分别安装python和python-pip。

Debian/Ubuntu上运行:

sudo apt update && sudo apt install python3 python3-pip

Arch及其衍生版本上运行:

sudo pacman -Syu python python-pip

你可以参考你各自操作系统的文档以了解更多细节。

一旦安装了python3python3-pip ,我们就可以开始编写我们的脚本了。首先,我们将创建一个新的虚拟环境。这是为了确保我们为脚本安装的依赖项不会与全局安装的依赖项冲突。

首先,我们将为我们的项目创建一个新的项目目录

  • 在基于Linux 的系统上:
mkdir ./system-resource-viewer && cd ./system-resource-viewer
  • 在Windows上PowerShell :
New-Item -Type Directory -Path .\system-resource-viewer
Set-Location .\system-resource-viewer

现在我们将创建我们新的虚拟环境:

python -m venv virtualenv

要激活你的新的虚拟环境,请使用以下命令,这取决于你的外壳:

  • PowerShell:.\virtualenv\bin\Activate.ps1

  • Bash:./virtualenv/bin/activate

  • Fish。./virtualenv/bin/activate.fish

一旦虚拟环境被激活,你的提示符将以虚拟环境的名字为后缀,在我们的例子中,它是virtualenv 。你的提示符应该有这样的后缀:

Screenshot-from-2022-06-07-16-16-09

要停用虚拟环境,我们现在可以简单地运行deactivate ,你会看到(virtualenv) 的后缀已经被删除。现在让我们回到我们新创建的虚拟环境。

现在,为了安装psutil ,我们将使用pippip 是一个Python包管理器,它使安装Python库和包更加容易。要安装psutil ,请运行以下命令。

pip install psutil

这应该是预期的输出: Screenshot-from-2022-06-07-16-28-57

一旦psutil ,我们将创建一个新的文件,使用你喜欢的文本编辑器。我将使用VS Codium ,这是一个没有遥测功能的VS Code 的开源构建。

首先,我们将开始导入新安装的psutil 模块,像这样:

import psutil

为了列出目前处理器的总使用量,我们将使用cpu_percent 函数,像这样:

psutil.cpu_percent(interval=1)

我们在这里所做的是,我们从psutil 模块中调用了cpu_percent 函数,有一个可选的参数interval=1 ,它告诉该函数**"阻塞 "**1秒钟。这样可以得到一个更准确的结果。如果你不使用这个可选参数来运行这个函数,它仍然会返回数值(比使用interval ),但会更不准确。

为了得到单个内核的使用情况,我们可以使用以下相同的函数,将percpu 可选参数设置为True ,像这样:

per_cpu = psutil.cpu_percent(percpu=True)
# For individual core usage with blocking, psutil.cpu_percent(interval=1, percpu=True)
for idx, usage in enumerate(per_cpu):
    print(f"CORE_{idx+1}: {usage}%")

这是在我的系统上运行时的输出:

CORE_1: 6.1%
CORE_2: 8.9%
CORE_3: 1.0%
CORE_4: 11.9%
CORE_5: 3.0%
CORE_6: 5.1%
CORE_7: 34.0%
CORE_8: 2.9%

注意:你的系统的内核数量可能会有所不同,这取决于你的系统上安装了什么处理器。

为了获得整体的内存使用情况,我们将使用另一个名为virtual_memory 的函数,它返回一个NamedTuple ,我们可以这样调用这个函数

mem_usage = psutil.virtual_memory()

要获得你的系统内存的完整细节,你可以运行以下代码:

import psutil

mem_usage = psutil.virtual_memory()

print(f"Free: {mem_usage.percent}%")
print(f"Total: {mem_usage.total/(1024**3):.2f}G")
print(f"Used: {mem_usage.used/(1024**3):.2f}G")

这应该会产生下面的输出:

Free: 62.8%
Total: 11.51G
Used: 5.81G

现在我们已经学会了使用psutil 来显示整个系统的使用情况。但每个单独的进程又是怎样的呢?事实证明,psutil 可以为我们提供单独查看进程的能力,使用它们的PID(s) 或**"进程ID"。**让我们来试试。

首先,我们将得到我们的python实例的pid ,接下来,我们将尝试列出这个实例的属性。为了得到我们正在运行的python实例的pid ,我们需要使用另一个名为os 的库。幸运的是,这个库已经预装在python中。因此,我们可以立即开始工作。让我们先从该库中导入所需的函数:

from os import getpid

该函数getpid ,将返回我们当前Python实例的pid 。我们可以使用这个pid 来获得我们进程的属性:

my_process = psutil.Process(getpid())
print("Name:", my_process.name())
print("PID:", my_process.pid)
print("Executable:", my_process.exe())
print("CPU%:", my_process.cpu_percent(interval=1))
print("MEM%:", my_process.memory_percent())

这应该会产生一个类似于这个的输出:

Name: python3
PID: 7932
Executable: /usr/bin/python3.10
CPU%: 0.0
MEM%: 0.09907581155184199

每次我们运行程序时,输出可能会发生变化,因为我们系统中的任何进程都不会使用固定的系统资源。

我们已经知道,我们可以得到每个单独进程的系统利用率,但我们如何得到目前在我们系统中运行的所有进程的属性呢?

为了回答这个问题,我们将使用psutil.pids() 方法。顾名思义,这个函数返回给我们一个当前活动进程的pids 列表。

例如,下面的脚本应该返回我们系统中当前运行的进程的名称:

for pid in psutil.pids():
    print(psutil.Process(pid).name())

由于这段代码的输出量相当大,我只能为我们的演示展示其中的一大部分:

systemd
gnome-session
dbus-daemon
pulesaudio
gjs
dconf-service
...

让我们试着获取进程的属性,为此我们将使用下面的脚本:

for process in [psutil.Process(pid) for pid in psutil.pids()]:
    print('Name:', process.name())
    print('CPU%:', process.cpu_percent(interval=0.5))
    print('MEM%:', process.memory_percent())

我们将得到一个与此类似的输出:

--------------------------
Name: pipewire
CPU%: 0.0
MEM%: 0.05258639228520845
--------------------------
Name: firefox
CPU%: 0.0
MEM%: 4.53346393226263
--------------------------
Name: Xwayland
CPU%: 2.0
MEM%: 0.7896242773513026
--------------------------
Name: gsd-xsettings
CPU%: 0.0
MEM%: 0.567051626450392
--------------------------

但是,突然间,我们面临这个错误:

Traceback (most recent call last):
  File "Projects/system-resource-viewer/system-resource-viewer.py", line 7, in <module>
    print("Name:", process.name())
  File "Projects/system-resource-viewer/virtualenv/lib/python3.10/site-packages/psutil/__init__.py", line 621, in name
    name = self._proc.name()
  File "Projects/system-resource-viewer/virtualenv/lib/python3.10/site-packages/psutil/_pslinux.py", line 1642, in wrapper
    return fun(self, *args, **kwargs)
  File "Projects/system-resource-viewer/virtualenv/lib/python3.10/site-packages/psutil/_pslinux.py", line 1735, in name
    name = self._parse_stat_file()['name']
  File "Projects/system-resource-viewer/virtualenv/lib/python3.10/site-packages/psutil/_pslinux.py", line 1649, in wrapper
    raise NoSuchProcess(self.pid, self._name)
psutil.NoSuchProcess: process no longer exists (pid=10055)

这是因为在上面的列表中产生的一个进程[psutil.Process(pid) for pid in psutil.pids()] ,在我们看它之前就被终止了。为了防止这种情况,我们首先需要验证,当我们试图查询进程属性时,进程pid 是有效的。我们可以使用下面的函数psutil.pid_exits() ,这将使我们能够在上面创建的列表中得到有效的进程,然后希望不会面临这个问题。另外,我们可以在打印CPU利用率之前,先打印进程使用的内存,这样它的阻塞间隔可能不会影响我们的结果。我们的新脚本应该是这样出现的

from os import get_terminal_size

import psutil

for process in [psutil.Process(pid) for pid in psutil.pids()]:
    if psutil.pid_exists(process.pid):
        print("Name:", process.name())
        print("MEM%:", process.memory_percent())
        print("CPU%:", process.cpu_percent(interval=0.5))
        print("-" * get_terminal_size().lines)

现在我们可以测试一下,看看它在大多数情况下不会引发任何错误。

我们总是需要确保我们正在检查的进程确实存在,即使在检查了一个进程是否存在之后,也有可能在我们到达上述任何一个打印语句之前,该进程就已经终止了,不幸的是,这种情况是无法避免的,因此我们需要通过使用try catch块来处理这种情况,为了防止部分显示进程的属性,我们将把变量数据存储到一些变量中,如果出现错误,我们将不必打印有效的属性,如pid ,并可以继续前进。
我们的新脚本现在可以采用这种形式。

# Imports

for process in [psutil.Process(pid) for pid in psutil.pids()]:
    try:
        name = process.name()
        mem = process.memory_percent()
        cpu = process.cpu_percent(interval=0.5)
    except psutil.NoSuchProcess as e:
        print(e.pid, "killed before analysis")
    else:
        print("Name:", name)
        print("CPU%:", cpu)
        print("MEM%:", mem)
    print("-" * get_terminal_size().lines)

而我们的输出将与此类似:

12586 killed before analysis
--------------------------
Name: kworker/6:2-events_freezable
CPU%: 0.0
MEM%: 0.0
--------------------------
12601 killed before analysis
--------------------------
Name: kworker/7:0-events
CPU%: 0.0
MEM%: 0.0
--------------------------
12777 killed before analysis
--------------------------
Name: kworker/3:2-mm_percpu_wq
CPU%: 2.0
MEM%: 0.0
--------------------------

现在我们将知道哪个进程被终止了,并创建了一个流体脚本,打印所有进程的属性。

结尾注释

psutil 为开发者提供了极大的灵活性和能力来查看和监控系统资源,以及进程。它允许更多的功能,比如杀死一个进程,向进程发送信号,这些在OpenGenus的这篇文章中没有讨论。