本文深入介绍基础的 Linux 进程管理技术。您将学习如何:理解进程优先级
设置进程优先级
更改进程优先级
本文帮助您准备 Linux Professional Institute's Junior Level Administration (LPIC-1) 考试 101 的 103 主题下的 103.6 考核目标。该考核目标的权值为 2。
为了从本文获得最大的收益,您应该具备基础的 Linux 知识,并且具有一个能够正常运行的 Linux 系统,以便练习本文讨论的命令。不同版本的程序输出的结果的格式可能不同,因此您的结果可能与本文图片和清单所示的结果有所不同。本文的例子显示的结果来自于 Ubuntu 9.10 (Karmic Koala) 发行版。本文以上一篇文章 “学习 Linux,101:创建、监控和终止进程” 为基础。
联系 Ian
Ian 是我们最受欢迎并且很多产的作者之一。查看 Ian 的个人资料 并与他和 My developerWorks 上的其他作者和读者联系。
Linux 与其他现代操作系统一样,也可以运行多个进程。它在多个进程之间共享 CPU 和其他资源。如果一个进程占用了 100% 的 CPU,那么其他进程将无法响应。
如果运行 top 命令,默认将按照 CPU 使用量的降序显示进程,如清单 1 所示。在上一篇文章 “学习 Linux,101:创建、监控和终止进程” 中,我们展示了一个简易的数字时钟脚本,它每 30 秒在控制台打印,其他时间不执行任何操作。如果我们运行该进程,它可以不会出现在 top 的输出列表上,因为该进程大部分时间不使用 CPU。
top - 08:00:52 up 1 day, 10:20, 5 users, load average: 0.04, 0.08, 0.04
Tasks: 172 total, 1 running, 171 sleeping, 0 stopped, 0 zombie
Cpu(s): 3.7%us, 0.3%sy, 0.0%ni, 95.6%id, 0.0%wa, 0.0%hi, 0.3%si, 0.0%st
Mem: 4057976k total, 1777976k used, 2280000k free, 225808k buffers
Swap: 10241428k total, 0k used, 10241428k free, 655796k cached
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
11220 ian 20 0 555m 106m 27m S 8 2.7 36:06.16 firefox
7 root 15 -5 0 0 0 S 1 0.0 10:59.36 ksoftirqd/1
10849 ian 20 0 212m 15m 10m S 0 0.4 0:08.11 gnome-terminal
1 root 20 0 19584 1888 1196 S 0 0.0 0:00.83 init
2 root 15 -5 0 0 0 S 0 0.0 0:00.01 kthreadd
3 root RT -5 0 0 0 S 0 0.0 0:00.02 migration/0
4 root 15 -5 0 0 0 S 0 0.0 0:01.08 ksoftirqd/0
5 root RT -5 0 0 0 S 0 0.0 0:00.00 watchdog/0
6 root RT -5 0 0 0 S 0 0.0 0:00.03 migration/1
您的系统可能有很多命令都会占用大量 CPU。比如视频编辑工具、转换不同图片格式的程序或者音频编码转换程序(如将 mp3 转换为 ogg)等。
如果您只有一个 CPU 或者 CPU 的数量有限,那么必须决定如何在几个计算进程之间共享这些有限的 CPU 资源。通常的做法是,选择一个要执行的进程,并让它在短时间内运行(这个时间称为时间片),或者一直运行到它需要等待的一些事件,如要完成的 IO 等。为了确保重要的进程能够得到 CPU,这种选择是基于调度优先级 进程的。清单 1 中的 NI 列展示了调度优先级或者说每个进程的niceness。niceness 的范围一般从 -20 到 19,-20 表示调度优先级最高,19 表示优先级最低。
除了 top 命令之外,您还可以使用 ps 命令显示 niceness 值。您可以按照从文章 “学习 Linux,101:创建、监控和终止进程” 中学到的方式自定义输出,也可以使用 -l 选项获取长清单。ps -l 的结果如清单 2 所示。如果使用 top 命令,请在 NI 列中查看 niceness 值。
ian@attic4:~$ ps -l
F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD
0 S 1000 26502 26501 0 80 0 - 5368 wait pts/4 00:00:00 bash
0 R 1000 27046 26502 0 80 0 - 1684 - pts/4 00:00:00 ps
从清单 1 和清单 2 中我们可以猜测出,常规用户所启用进程的 niecess 的默认值是 0。在当前的 Linux 系统中通常是这样。您可以运行 nice 命令且不带任何参数,以此验证您的 shell 和系统中的该值,如清单 3 所示。
ian@attic4:~$ nice
0
在查看如何设置或更改 niceness 值之前,我们先构建一个 CPU 密集型小脚本,演示 niceness 的工作方式。
我们将创建一个小脚本,它占用较多的 CPU,但执行的操作很简单。该脚本有两个输入:计数和标签。它打印标签以及当前的日期和时间,然后旋转,递减计数,直到它到达 0,最后再次打印标签和日期。该脚本如清单 4 所示,它没有任何错误检查机制,也不是非常稳定,但是它足以满足我们的演示需要。
ian@attic4:~$ echo 'x="$1"'>count1.sh
ian@attic4:~$ echo 'echo "$2" $(date)'>>count1.sh
ian@attic4:~$ echo 'while [ $x -gt 0 ]; do x=$(( x-1 ));done'>>count1.sh
ian@attic4:~$ echo 'echo "$2" $(date)'>>count1.sh
ian@attic4:~$ cat count1.sh
x="$1"
echo "$2" $(date)
while [ $x -gt 0 ]; do x=$(( x-1 ));done
echo "$2" $(date)
如果在系统上运行该脚本,它的输出将类似于清单 5。您可能需要增加计数值以查看时间的不同,具体取决于您系统的速度。该脚本将占用大量 CPU,等会我们就会看到这一点。如果您的默认 shell 不是 Bash,如果您的脚本无法运行,那么可以使用下文所示的第二种调用形式。如果您使用的不是自己的工作站,运行脚本前请确保占用大量 CPU 不会导致不良影响。
ian@attic4:~$ sh count1.sh 10000 A
A Wed Jan 20 08:34:16 EST 2010
A Wed Jan 20 08:34:16 EST 2010
ian@attic4:~$ bash count1.sh 99000 A
A Wed Jan 20 08:34:20 EST 2010
A Wed Jan 20 08:34:22 EST 2010
到目前为止一切顺利。现在让我们创建一个在后台运行的脚本,并启动 top 命令查看脚本所用 CPU 的命令清单(请参见之前的文章 “学习 Linux,101:Linux 命令行” 了解最新的命令清单)。命令清单如清单 6 所示,top 的输出见清单 7。
ian@attic4:~$ (sh count1.sh 5000000 A&);top
top - 15:41:15 up 1 day, 17:59, 6 users, load average: 0.20, 0.06, 0.02
Tasks: 169 total, 2 running, 167 sleeping, 0 stopped, 0 zombie
Cpu(s): 52.1%us, 0.7%sy, 0.0%ni, 47.3%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
Mem: 4057976k total, 1393772k used, 2664204k free, 235596k buffers
Swap: 10241428k total, 0k used, 10241428k free, 662592k cached
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
26756 ian 20 0 4004 588 496 R 100 0.0 0:03.53 sh
11220 ian 20 0 555m 101m 27m S 5 2.6 57:58.07 firefox
26757 ian 20 0 19132 1364 980 R 0 0.0 0:00.03 top
1 root 20 0 19584 1888 1196 S 0 0.0 0:00.89 init
2 root 15 -5 0 0 0 S 0 0.0 0:00.01 kthreadd
不错。我们只使用了一个简单的脚本就占用了系统中一个 CPU 100% 的资源。如果希望占用多个 CPU,您可以在命令清单中添加对count1.sh 的调用。如果运行过类似的作业,您会发现我们将无法在系统上执行其他工作(其他用户也是如此)。
现在我们可以让 CPU 持续忙碌一段时间,我们了解如何设置进程的优先级。目前我们学到的内容总结如下:Linux 和 UNIX® 系统使用有 40 个优先级的优先级系统,范围从 -20(最高优先级)到 19(最低优先级)。
常规用户启动的进程优先级一般是 0。
ps 命令可以使用 -l 选项显示优先级(例如,nice 或 NI、level)。
nice 命令显示我们的默认优先级。
nice 命令还可以用来启动具有不同优先级的进程。使用 -n 或 (--adjustment) 选项时带一个负值可以增加优先级值,带一个正值将减少优先级值。记住,具有最低优先级值的进程运行时有最高调度优先级,因此可以这样记忆,增加优先级值对于其他进程而言更好(nice)。注意,您必须是超级用户(根用户)才能调低优先级值。换句话说,常规用户通常只能增加它们的优先级值。
为了演示如何使用 nice 设置优先级,首先同时在不同的 subshell 中启动两个 count1.sh 脚本的副本,但是将其中一个的 nice 值设置为最大值 19。一会儿之后,我们使用 ps -l 显示进程状态,包括 niceness。最后,我们添加任意 30 秒的休眠时间,确保两个 subshell 完成之后命令序列完成。这样一来,我们在等待输出时不会得到新的提示。结果如清单 8 所示。
ian@attic4:~$ (sh count1.sh 2000000 A&);(nice -n 19 sh count1.sh 2000000 B&);\
> sleep 1;ps -l;sleep 10
A Thu Jan 21 14:38:39 EST 2010
B Thu Jan 21 14:38:39 EST 2010
F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD
0 R 1000 946 1 99 80 0 - 1001 - pts/3 00:00:01 sh
0 R 1000 948 1 99 99 19 - 1001 - pts/3 00:00:01 sh
0 R 1000 952 32408 0 80 0 - 1684 - pts/3 00:00:00 ps
0 S 1000 32408 32407 0 80 0 - 5368 wait pts/3 00:00:02 bash
A Thu Jan 21 14:38:45 EST 2010
B Thu Jan 21 14:38:45 EST 2010
您对两个作业同时完成感到奇怪吗?我们的优先级设置怎么了?记住,脚本占用了一个 CPU。这个系统运行在 AMD Athlon™ 7750 双核处理器上,它的负载很轻,每个内核运行一个进程,不需要进行优化。
那么,让我们使用 4 个不同的 niceness 水平(0、6、12、18)启动 4 个进程查看会发生什么情况。我们将增加每个进程的忙碌计数参数使之运行的时间更长一些。查看清单 9 之前,请根据您了解的内容,预期一下会发生什么情况。
ian@attic4:~$ (sh count1.sh 5000000 A&);(nice -n 6 sh count1.sh 5000000 B&);\
> (nice -n 12 sh count1.sh 5000000 C&);(nice -n 18 sh count1.sh 5000000 D&);\
> sleep 1;ps -l;sleep 30
A Thu Jan 21 16:06:00 EST 2010
C Thu Jan 21 16:06:00 EST 2010
D Thu Jan 21 16:06:00 EST 2010
B Thu Jan 21 16:06:00 EST 2010
F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD
0 R 1000 1422 1 94 80 0 - 1001 - pts/3 00:00:00 sh
0 R 1000 1424 1 42 86 6 - 1001 - pts/3 00:00:00 sh
0 R 1000 1427 1 56 92 12 - 1001 - pts/3 00:00:00 sh
0 R 1000 1431 1 14 98 18 - 1001 - pts/3 00:00:00 sh
0 R 1000 1435 32408 0 80 0 - 1684 - pts/3 00:00:00 ps
0 S 1000 32408 32407 0 80 0 - 5368 wait pts/3 00:00:02 bash
A Thu Jan 21 16:06:14 EST 2010
B Thu Jan 21 16:06:17 EST 2010
C Thu Jan 21 16:06:26 EST 2010
D Thu Jan 21 16:06:30 EST 2010
使用 4 个不同的优先级我们发现,每个作业按照优先级顺序完成。请自行尝试不同的 nice 值演示各种可能的情况。
使用 nice 启动进程最后要注意的一点是:使用 nohup 命令时,不能使用命令清单或管道作为 nice 的参数。
如果您正好启动了一个进程,但意识到它应该以不同的优先级运行,那么有一种方法可以在启动之后对其进行更改,即使用 renice命令。您可以为进程指定一个绝对优先级(不是调整值),进程的更改如清单 10 所示。
ian@attic4:~$ sh count1.sh 10000000 A&
[1] 1537
ian@attic4:~$ A Thu Jan 21 16:17:16 EST 2010
sh count1.sh 1renice 1 1537;ps -l 1537
1537: old priority 0, new priority 1
F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD
0 R 1000 1537 32408 99 81 1 - 1001 - pts/3 0:13 sh count1.sh 100
ian@attic4:~$ renice +3 1537;ps -l 1537
1537: old priority 1, new priority 3
F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD
0 R 1000 1537 32408 99 83 3 - 1001 - pts/3 0:18 sh count1.sh 100
记住,您必须是超级用户才能为进程指定更高的调度优先级,或者说让它们的 nice 值更低。
您可以在手册上找到有关 nice 和 renice 的更多信息。