Contents

监视Linux上的进程线程计数

1. 简介

现代 CPU 由多个内核组成。因此,为了利用多核处理器的强大功能,应用程序通常在多线程进程上运行。有时,我们可能需要有关特定进程使用多少线程的信息。在本文中,我们将向您介绍可用于检查和监控线程计数数据的所有工具和命令。

我们假设线程和进程的概念是已知的。因此,如果您不熟悉或想了解更多关于线程和进程之间的区别,请务必阅读我们的文章Linux 进程与线程

2. 检查线程数

在本节中,我们将了解如何获取进程的即时线程计数信息。总而言之,我们有几种选择。

2.1.使用ps命令

命令 ps 显示有关计算机上当前活动进程的信息。组合选项*-e-f是我们可以用来以格式化方式获取每个进程的信息的标准方法。同样,我们可以附加-L选项让ps*报告附加线程信息:

$ ps -eLf
UID          PID    PPID     LWP  C NLWP STIME TTY          TIME CMD
root           1       0       1  0    1 12:00 ?        00:00:01 /sbin/init splash
root           2       0       2  0    1 12:00 ?        00:00:00 [kthreadd]
root           3       2       3  0    1 12:00 ?        00:00:00 [rcu_gp]
root           4       2       4  0    1 12:00 ?        00:00:00 [rcu_par_gp]
root           6       2       6  0    1 12:00 ?        00:00:00 [kworker/0:0H-events_highpri]
root           9       2       9  0    1 12:00 ?        00:00:00 [mm_percpu_wq]
root          10       2      10  0    1 12:00 ?        00:00:00 [rcu_tasks_rude_]
root          11       2      11  0    1 12:00 ?        00:00:00 [rcu_tasks_trace]
root          12       2      12  0    1 12:00 ?        00:00:00 [ksoftirqd/0]
root          13       2      13  0    1 12:00 ?        00:00:00 [rcu_sched]
root          14       2      14  0    1 12:00 ?        00:00:00 [migration/0]
root          15       2      15  0    1 12:00 ?        00:00:00 [idle_inject/0]
root          16       2      16  0    1 12:00 ?        00:00:00 [cpuhp/0]
root          17       2      17  0    1 12:00 ?        00:00:00 [cpuhp/1]
.
.
.
blogdemo    1970    1350    1970  0    5 12:01 ?        00:00:01 /usr/libexec/gnome-terminal-server
blogdemo    1970    1350    1971  0    5 12:01 ?        00:00:00 /usr/libexec/gnome-terminal-server
blogdemo    1970    1350    1972  0    5 12:01 ?        00:00:00 /usr/libexec/gnome-terminal-server
blogdemo    1970    1350    1973  0    5 12:01 ?        00:00:00 /usr/libexec/gnome-terminal-server
blogdemo    1970    1350    1977  0    5 12:01 ?        00:00:00 /usr/libexec/gnome-terminal-server
blogdemo    1978    1970    1978  0    1 12:01 pts/0    00:00:00 bash
blogdemo    1996    1350    1996  0    3 12:02 ?        00:00:00 /usr/libexec/gvfsd-metadata
blogdemo    1996    1350    1997  0    3 12:02 ?        00:00:00 /usr/libexec/gvfsd-metadata
blogdemo    1996    1350    1998  0    3 12:02 ?        00:00:00 /usr/libexec/gvfsd-metadata
blogdemo    1999    1607    1999  0    4 12:02 ?        00:00:00 update-notifier
blogdemo    1999    1607    2002  0    4 12:02 ?        00:00:00 update-notifier
blogdemo    1999    1607    2003  0    4 12:02 ?        00:00:00 update-notifier
blogdemo    1999    1607    2004  0    4 12:02 ?        00:00:00 update-notifier
root        2139       2    2139  0    1 12:07 ?        00:00:00 [kworker/u4:1-events_unbound]
root        2149       2    2149  0    1 12:15 ?        00:00:00 [kworker/1:1-cgroup_destroy]
root        2240       2    2240  0    1 12:32 ?        00:00:00 [kworker/0:1-events]
root        2241       2    2241  0    1 12:32 ?        00:00:00 [kworker/0:3-inet_frag_wq]
root        2247       2    2247  0    1 12:36 ?        00:00:00 [kworker/u4:0-events_unbound]
root        2298       2    2298  0    1 12:43 ?        00:00:00 [kworker/u4:2]
root        2335       2    2335  0    1 12:44 ?        00:00:00 [kworker/1:0-cgroup_destroy]
root        2336       2    2336  0    1 12:44 ?        00:00:00 [kworker/0:0-events]
blogdemo    2346    1978    2346  0    1 12:45 pts/0    00:00:00 ps -eLf

在输出中,NLWP(轻量级进程数)列指示附加到该特定进程的线程数。例如,当我们查看一个 NLWP 值大于 1 的进程时,我们可以看到它之后的相应行数具有相同的 PID 值。

但是,如果我们不想接收每个进程的所有这些杂乱信息并且我们只搜索特定进程的线程数,我们可以使用ps和*-o*选项:

$ ps -o nlwp 1970
NLWP
   5

这里nlwp表示我们上面用来获取线程数信息的列,1970是一个进程的PID。正如我们所见,这个进程同时运行了五个线程。如果我们愿意,我们可以使用thcount而不是nlwp来获得相同的结果:

$ ps -o thcount 1970
THCNT
    5

2.2. 检查*/proc*目录

以类似的方式,我们可以检查*/proc目录中的线程计数数据。/proc*是一个虚拟文件系统,包含有关进程的各种信息。我们来看看我们能得到哪些信息:

$ ls /proc/1970/task/
1970  1971  1972  1973  1977

正如我们在上面清楚地看到的,PID 为 1970 的进程包含五个线程。事实上,这个结果与我们之前使用命令ps得到的结果相匹配。此外,我们可以验证这些目录名称是否与LWP列下的相应结果完全相同。

查找线程计数信息的另一种方法是检查 方便文件夹下的status文件:

$ cat /proc/1970/status | grep Threads
Threads:	5

3. 监控线程数

到目前为止,我们已经研究了通过使用几种方法来获得即时结果。现在让我们看看我们想要实时监控状态的情况。

3.1. 将之前的命令与watch结合起来

当我们使用 watch工具结合上一节提到的命令时,可以实时监控任意进程的线程状态。我们还可以使用*-n*选项以秒为单位指定更新间隔。让我们看一个例子:

$ watch -n 1 ps -o thcount 1970
Every 1,0s: ps -o thcount 1970                                          blogdemo: Tue Mar 29 16:35:30 2022
THCNT
    5

请注意,上述结果每秒刷新一次。 watch每秒运行命令 ps -o thcount 1970并将输出显示回控制台。

3.2. 使用top工具

*top *是一个内置程序,用于报告 CPU 使用率和内存状态等系统信息。我们可以使用此工具获取每个进程的线程数信息,但默认情况下它是禁用的。因此,我们将不得不手动调整该工具。首先,我们需要进入实用程序:

$ top

然后,在按下 f键后,我们将看到top可以显示的指标列表。让我们用d相应地选择nTH字段, 然后按q返回主界面:

top - 15:53:11 up  3:52,  1 user,  load average: 0,14, 0,13, 0,09
Tasks: 198 total,   1 running, 197 sleeping,   0 stopped,   0 zombie
%Cpu(s):  1,7 us,  0,7 sy,  0,0 ni, 97,3 id,  0,0 wa,  0,0 hi,  0,3 si,  0,0 st
MiB Mem :    971,2 total,     90,5 free,    543,3 used,    337,4 buff/cache
MiB Swap:    923,3 total,    718,7 free,    204,6 used.    273,4 avail Mem 
    PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND                         nTH 
   1622 blogdemo  20   0 4218272 304356  76152 S   2,3  30,6   2:22.32 gnome-shell                     12 
   1416 blogdemo  20   0  286816  58088  24356 S   1,7   5,8   0:39.93 Xorg                            2 
   1970 blogdemo  20   0  818528  43312  30420 S   1,0   4,4   0:16.31 gnome-terminal-                 5 
   1547 blogdemo  20   0  158108   2068   1984 S   0,3   0,2   0:13.21 VBoxClient                      4 
      1 root      20   0  167660   7924   5496 S   0,0   0,8   0:01.38 systemd                         1 
      2 root      20   0       0      0      0 S   0,0   0,0   0:00.00 kthreadd                        1 
      3 root       0 -20       0      0      0 I   0,0   0,0   0:00.00 rcu_gp                          1 
      4 root       0 -20       0      0      0 I   0,0   0,0   0:00.00 rcu_par_gp                      1 
      6 root       0 -20       0      0      0 I   0,0   0,0   0:00.00 kworker/0:0H-events_highpri     1 
      9 root       0 -20       0      0      0 I   0,0   0,0   0:00.00 mm_percpu_wq                    1 
     10 root      20   0       0      0      0 S   0,0   0,0   0:00.00 rcu_tasks_rude_                 1 
     11 root      20   0       0      0      0 S   0,0   0,0   0:00.00 rcu_tasks_trace                 1 
     12 root      20   0       0      0      0 S   0,0   0,0   0:00.21 ksoftirqd/0                     1 
     13 root      20   0       0      0      0 I   0,0   0,0   0:00.53 rcu_sched                       1 
     14 root      rt   0       0      0      0 S   0,0   0,0   0:00.03 migration/0                     1 
     15 root     -51   0       0      0      0 S   0,0   0,0   0:00.00 idle_inject/0                   1 
     16 root      20   0       0      0      0 S   0,0   0,0   0:00.00 cpuhp/0                         1 
     17 root      20   0       0      0      0 S   0,0   0,0   0:00.00 cpuhp/1                         1 

需要注意的是**,PID 为 1970 的进程有五个线程,正如我们在之前的方法中看到的那样**。

我们还可以使用更现代的版本 htop。这个想法是一样的。但是,请记住,top通常是内置的,而我们可能需要手动安装htop