为什么htop显示比ps更多的进程
1. 概述
作为 Linux 用户,我们经常希望确定系统上正在运行的进程的总数。此外,有时我们可能想要调查特定程序或命令在做什么。为此,我们可以依赖不同的工具,例如htop 和*ps *。
在本教程中,我们将在监控进程和线程时检查这些命令的输出。
2. 如何安装htop
htop是一个交互式工具,可以让我们实时查看和管理正在运行的进程和线程。它也是一个非常有用的命令来监控系统资源,例如 CPU 和内存使用情况。
让我们看看我们如何分别在 Ubuntu/Debian 和 CentOS 上安装这个实用程序。
对于 Ubuntu/Debian:
$ sudo apt install htop
对于 CentOS:
$ yum install epel-release
$ yum install htop
$ htop -v
htop 2.2.0 - (C) 2004-2019 Hisham Muhammad
Released under the GNU GPL.
在接下来的部分中,我们将使用htop的 2.2.0 版本。
3. 比较htop和ps的输出
htop和 ps都是 进程管理器。让我们看看它们默认为特定进程显示的内容。
3.1. 使用htop检查mysqld进程
使用htop,我们可以从命令行将输出限制为特定的进程 ID。为了说明手头的问题,让我们将 MariaDB 服务器进程 ID 作为值传递给–pid选项:
$ htop --pid=$(pidof mysqld)
1 [|| 2.6%] Tasks: 51, 43 thr; 2 running
2 [ 0.0%] Load average: 0.00 0.02 0.05 Mem[||||||||||||||||||||||||||||||||||||||||||||| 397M/991M] Uptime: 04:45:44
Swp[ 0K/2.00G]
PID USER PRI NI VIRT RES SHR S CPU% MEM% TIME+ Command
17173 mysql 20 0 948M 88316 7108 S 0.7 8.7 0:00.73 /usr/libexec/mysqld --basedir=/usr --datadir=/data/lib/mysql --plugin-dir=/usr/lib64/mysql/
17184 mysql 20 0 948M 88316 7108 S 0.0 8.7 0:00.03 /usr/libexec/mysqld --basedir=/usr --datadir=/data/lib/mysql --plugin-dir=/usr/lib64/mysql/
17177 mysql 20 0 948M 88316 7108 S 0.0 8.7 0:00.03 /usr/libexec/mysqld --basedir=/usr --datadir=/data/lib/mysql --plugin-dir=/usr/lib64/mysql/
...
17193 mysql 20 0 948M 88316 7108 S 0.0 8.7 0:00.00 /usr/libexec/mysqld --basedir=/usr --datadir=/data/lib/mysql --plugin-dir=/usr/lib64/mysql/
17202 mysql 20 0 948M 88316 7108 S 0.0 8.7 0:00.00 /usr/libexec/mysqld --basedir=/usr --datadir=/data/lib/mysql --plugin-dir=/usr/lib64/mysql/
17203 mysql 20 0 948M 88316 7108 S 0.0 8.7 0:00.00 /usr/libexec/mysqld --basedir=/usr --datadir=/data/lib/mysql --plugin-dir=/usr/lib64/mysql/
F1Help F2Setup F3Search F4Filter F5Tree F6SortByF7Nice -F8Nice +F9Kill F10Quit
在这里,我们使用*pidof 命令来查找正在运行的 MariaDB 程序名称的PID*。然后,使用命令替换 ,我们将pidof mysqld命令替换为其实际输出。
3.2. 使用ps列出mysqld进程
另一方面,让我们结合grep 命令和ps来根据mysqld 进程 ID 过滤输出:
$ ps -e -o pid,user,command | grep $(pidof mysqld) | grep -v grep
17173 mysql /usr/libexec/mysqld --basedir=/usr --datadir=/data/lib/mysql --plugin-dir=/usr/lib64/mysql/plugin --log-error=/data/lib/mysql/log/mariadb.log --pid-file=/data/lib/mysql/run/mariadb.pid --socket=/data/lib/mysql/mysql.sock
在上面,我们将*-e选项传递给ps以选择所有进程,并将-o选项传递给仅打印某些字段。此外,我们使用带有-v选项的grep命令从最终输出中排除grep*本身。
我们注意到htop与ps输出相比显示了更多的进程。在下一节中,我们将讨论我们刚刚获得的输出。
4. 为什么进程数不同?
事实证明,htop和ps都从/proc 文件系统中读取了有关正在运行的进程和线程数的详细信息。更具体地说,是*/proc/pid目录和/proc/pid/task/tid*的子目录。
让我们列出并计算*/proc/pid/task/下的子目录,将pid替换为正在运行的 MariaDB 服务器PID*:
$ ls /proc/$(pidof mysqld)/task
17173 17177 17178 17179 17180 17181 17182 17183 17184 17185 17186 17188 17189 17190 17191 17192 17193 17202 17203
$ ls -1 /proc/$(pidof mysqld)/task | wc -l
19
我们从上面的输出推断,与ps不同,htop命令默认显示正在运行的进程及其对应的各个线程。
htop旨在提供尽可能多的有关系统中正在发生的事情的信息。结果,它显示用户线程而不是隐藏它们。例如,系统管理员可以在多线程应用程序中发现问题,同时监控其相关线程的 CPU 使用率。然而,一些 Linux 用户更喜欢禁用此设置,因为他们发现在htop输出中显示所有线程不太有用。
5. 使用htop 的线程
在 Linux 中,我们有用户空间和内核空间线程 。用户线程与用户应用程序相关联,内核线程由操作系统创建和管理。
** htop默认显示用户线程并隐藏内核线程**。接下来,让我们检查一下如何修改此行为。
5.1. 用户线程
我们可以自定义htop配置来禁用用户线程的可见性。为了证明这一点,我们执行htop –pid=$(pidof mysqld),然后:
- 转到设置
- 显示选项
- 检查隐藏用户态进程线程
- 按F10
同样,我们可以简单地按H隐藏用户线程。
在上述更改之后,我们将输出限制为仅主 MariaDB 进程:
PPID PID USER PRI NI VIRT RES SHR S CPU% MEM% TIME+ Command
17007 17173 mysql 20 0 948M 88316 7108 S 0.7 8.7 0:01.07 /usr/libexec/mysqld --basedir=/usr --datadir=/data/lib/mysql --plugin-dir=/usr/lib64/
现在我们看到了ps向我们展示的相同过程。此外,让我们探讨两个流程管理器之间的另一个比较点。
5.2. 内核线程
从版本 2.2.0 开始,** htop通过检查*/proc/pid/cmdline是否为空来识别内核线程**。但是,最新的htop版本会根据/proc/pid/stat中的PF_KTHREAD*位值检测内核线程。
我们可以列出默认禁用的内核线程。首先,让我们启动htop然后添加一个新列:
- 转到设置
- 列
- 可用列
- 选择PPID列
接下来,让我们点击K:
PPID PID USER PRI NI VIRT RES SHR S CPU% MEM% TIME+ Command
2 20265 root 20 0 0 0 0 S 0.7 0.0 0:00.08 kworker/1:1
17007 17173 mysql 20 0 948M 88316 7108 S 0.0 8.7 0:01.17 /usr/libexec/mysqld --basedir=/usr --datadir=/data/lib/mysql --plugin-dir=/usr/lib64/
17007 17182 mysql 20 0 948M 88316 7108 S 0.0 8.7 0:00.06 /usr/libexec/mysqld --basedir=/usr --datadir=/data/lib/mysql --plugin-dir=/usr/lib64/
...
2 14 root 20 0 0 0 0 S 0.0 0.0 0:00.18 ksoftirqd/1
2 16 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 kworker/1:0H
2 18 root 20 0 0 0 0 S 0.0 0.0 0:00.00 kdevtmpfs
从上面我们也看到了内核线程。例如,kworker/0:0H与PPID =2 (Kthreadd作为父进程)。
此外, htop输出的右上角显示了一些关于总运行进程的有用信息:
Tasks: 53, 43 thr, 78 kthr; 2 running
这意味着根据htop,我们总共有 53 个进程、43 个用户线程、78 个内核线程和 2 个处于运行状态的任务。让我们将其与 ps进行比较。
6. 如何用ps列出线程
我们可以修改默认的ps输出以显示有关进程和线程的详细信息。要选择所有进程并显示线程,我们可以将*-eLf标志传递给ps*命令。
作为说明,让我们将输出限制为前 5 个mysqld线程,同时仍保留标头名称:
$ ps -eLf | head -n 1 ; ps -eLf | grep $(pidof mysqld) | head -n 5
UID PID PPID LWP C NLWP STIME TTY TIME CMD
mysql 17173 17007 17173 0 19 13:30 ? 00:00:00 /usr/libexec/mysqld --basedir=/usr --datadir=/data/lib/mysql --plugin-dir=/usr/lib64/mysql/plugin --log-error=/data/lib/mysql/log/mariadb.log --pid-file=/data/lib/mysql/run/mariadb.pid --socket=/data/lib/mysql/mysql.sock
mysql 17173 17007 17177 0 19 13:30 ? 00:00:00 /usr/libexec/mysqld --basedir=/usr --datadir=/data/lib/mysql --plugin-dir=/usr/lib64/mysql/plugin --log-error=/data/lib/mysql/log/mariadb.log --pid-file=/data/lib/mysql/run/mariadb.pid --socket=/data/lib/mysql/mysql.sock
mysql 17173 17007 17178 0 19 13:30 ? 00:00:00 /usr/libexec/mysqld --basedir=/usr --datadir=/data/lib/mysql --plugin-dir=/usr/lib64/mysql/plugin --log-error=/data/lib/mysql/log/mariadb.log --pid-file=/data/lib/mysql/run/mariadb.pid --socket=/data/lib/mysql/mysql.sock
mysql 17173 17007 17179 0 19 13:30 ? 00:00:00 /usr/libexec/mysqld --basedir=/usr --datadir=/data/lib/mysql --plugin-dir=/usr/lib64/mysql/plugin --log-error=/data/lib/mysql/log/mariadb.log --pid-file=/data/lib/mysql/run/mariadb.pid --socket=/data/lib/mysql/mysql.sock
mysql 17173 17007 17180 0 19 13:30 ? 00:00:00 /usr/libexec/mysqld --basedir=/usr --datadir=/data/lib/mysql --plugin-dir=/usr/lib64/mysql/plugin --log-error=/data/lib/mysql/log/mariadb.log --pid-file=/data/lib/mysql/run/mariadb.pid --socket=/data/lib/mysql/mysql.sock
在上面的示例中,我们结合了*-Lf选项来添加LWP*(线程 ID)和NLWP(线程数)列。NLWP列显示我们有 19个mysqld线程。
最后,我们可以通过传递*–ppid* 和 -p选项来查看和统计内核线程的数量,分别根据父进程 ID 和进程 ID 进行选择:
$ ps --ppid 2 -p 2 --format pid,ppid,time,cmd
PID PPID TIME CMD
2 0 00:00:00 [kthreadd]
4 2 00:00:00 [kworker/0:0H]
6 2 00:00:00 [ksoftirqd/0]
7 2 00:00:00 [migration/0]
8 2 00:00:00 [rcu_bh]
9 2 00:00:01 [rcu_sched]
10 2 00:00:00 [lru-add-drain]
11 2 00:00:00 [watchdog/0]
...
6570 2 S 00:00:00 [kworker/1:0]
25359 2 S 00:00:00 [kworker/0:0]
25761 2 S 00:00:00 [kworker/1:2]
26957 2 S 00:00:00 [kworker/0:2]
在这种情况下,我们使用*–format*标志来指定列。
从上面的输出中,我们列出了内核线程kthreadd ( PID =2) 及其所有子线程 ( PPID =2)。
最后,让我们像使用htop一样计算内核线程的总数:
$ ps --ppid 2 -p 2 --format pid,ppid,state,time,cmd | tail -n +2 | wc -l
78
我们使用tail 命令跳过计算第一列标题。
如上所示,使用 ps 命令显示的内核线程数与使用 htop 显示的 kthr 数相同。