摘要:通过设置和改变进程的优先级来让进程获得所需要的运行时间片段。
本文讲帮你在如下几个方面打牢基础:
本文为备考LPIC-1的目标103.6,权重为2。
与其他大多数现代操作系统一样,Linux也能运行多个进程。这通过进程间共享CPU和其他资源完成。如果一个进程占用了100%的CPU,那么其他进程将会失去反应。
如果你运行top命令,默认情况下,会按照CPU占用率降序显示各个进程。前面的例子中,我们展示了一个Poor Man's Colck脚本,它每30秒打印一次当前时间,其它时间内则没有动作。top可能不会把这个进程显示出来,因为它大部分时间都没有使用CPU。
典型的top输出:
Mem: 3924872k total, 3429320k used, 495552k free, 529468k buffers Swap: 7574520k total, 0k used, 7574520k free, 1872160k cached PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 1580 mysql 20 0 870m 73m 6748 S 0.3 1.9 100:09.57 mysqld 14163 root 20 0 15024 1384 1008 R 0.3 0.0 0:00.06 top 1 root 20 0 19228 1532 1248 S 0.0 0.0 0:11.62 init 2 root 20 0 0 0 0 S 0.0 0.0 0:00.00 kthreadd 3 root RT 0 0 0 0 S 0.0 0.0 0:08.19 migration/0 4 root 20 0 0 0 0 S 0.0 0.0 0:10.33 ksoftirqd/0 5 root RT 0 0 0 0 S 0.0 0.0 0:00.00 migration/0 6 root RT 0 0 0 0 S 0.0 0.0 0:18.44 watchdog/0 7 root RT 0 0 0 0 S 0.0 0.0 0:08.87 migration/1 8 root RT 0 0 0 0 S 0.0 0.0 0:00.00 migration/1 9 root 20 0 0 0 0 S 0.0 0.0 0:14.39 ksoftirqd/1 10 root RT 0 0 0 0 S 0.0 0.0 0:18.44 watchdog/1 11 root RT 0 0 0 0 S 0.0 0.0 0:07.99 migration/2 12 root RT 0 0 0 0 S 0.0 0.0 0:00.00 migration/2 13 root 20 0 0 0 0 S 0.0 0.0 0:14.89 ksoftirqd/2 14 root RT 0 0 0 0 S 0.0 0.0 0:17.60 watchdog/2 15 root RT 0 0 0 0 S 0.0 0.0 0:06.82 migration/3 16 root RT 0 0 0 0 S 0.0 0.0 0:00.00 migration/3 17 root 20 0 0 0 0 S 0.0 0.0 0:05.61 ksoftirqd/3 18 root RT 0 0 0 0 S 0.0 0.0 0:17.79 watchdog/3 19 root 20 0 0 0 0 S 0.0 0.0 6:35.02 events/0 20 root 20 0 0 0 0 S 0.0 0.0 6:39.81 events/1 21 root 20 0 0 0 0 S 0.0 0.0 70:32.21 events/2 22 root 20 0 0 0 0 S 0.0 0.0 8:35.72 events/3 23 root 20 0 0 0 0 S 0.0 0.0 0:00.00 cgroup 24 root 20 0 0 0 0 S 0.0 0.0 0:00.00 khelper 25 root 20 0 0 0 0 S 0.0 0.0 0:00.00 netns 26 root 20 0 0 0 0 S 0.0 0.0 0:00.00 async/mgr 27 root 20 0 0 0 0 S 0.0 0.0 0:00.00 pm 28 root 20 0 0 0 0 S 0.0 0.0 0:45.88 sync_supers 29 root 20 0 0 0 0 S 0.0 0.0 0:53.20 bdi-default 30 root 20 0 0 0 0 S 0.0 0.0 0:00.00 kintegrityd/0 31 root 20 0 0 0 0 S 0.0 0.0 0:00.00 kintegrityd/1
你的系统中可能会有一些进程使用很多的CPU资源,如视频编辑工具、图片格式转换工具或音频格式转换工具,如mp3转为ogg。
当你的机器上只有一个或者有限个数的CPU时,你需要决定如何在多个竞争进程之间共享CPU资源。这通常是通过选中一个进程让它运行一段时间(时间片),或者让它停止运行直到它等待的事件如IO完成。为了确保重要的进程不会因为CPU资源缺乏而失去反应,这种选择是基于调度优先级的。上表中的NI列代表的是进程的调度优先级,也叫做niceness。优先级通常是在-20到19之间,其中-20代表最高优先级,19代表最低优先级。
除了top命令外,也可以使用ps命令来显示进程优先级。使用ps -l,其输出的NI列就是进程优先级。如下所示:
[root@centos192 ~]# ps -l F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD 4 S 0 14148 14146 0 80 0 - 27074 wait pts/1 00:00:00 bash 4 R 0 14548 14148 0 80 0 - 27030 - pts/1 00:00:00 ps
你能已经从上面的两个例子中猜出来了,至少由普通用户启动的进程的优先级是0。这对现在的Linux系统来说是正确的。这个默认值可以通过运行不带参数的nice命令来获取。
ot@centos192 ~]# nice 0
在我们学习如何设置和改变优先级之前,先构建一个CPU密集型的脚本,它将会展示优先级确实有影响。
我们将创建一个只使用CPU的小脚本。这个脚本使用两个输入参数,一个是计数值,一个是标签。首先会打印出这个标签和当前的系统时间,然后进入循环,每次循环都使得计数值减一,当计数值为0时终止循环,打印出标签和时间。这个测试脚本中没有进行错误检测也不是非常健壮,但是它可以说明问题了。
[root@centos192 ~]# echo 'x="$1"' > count1.sh [root@centos192 ~]# echo 'echo "$2" $(date)' >> count1.sh [root@centos192 ~]# echo 'while [ $x -gt 0 ]; do x=$((x-1)); done' >>count1.sh [root@centos192 ~]# echo 'echo "$2" $(date)' >>count1.sh [root@centos192 ~]# cat count1.sh x="$1" echo "$2" $(date) while [ $x -gt 0 ]; do x=$((x-1)); done echo "$2" $(date)
如果你在电脑上运行这个脚本,可能的输出如下:
[root@centos192 ~]# ./count1.sh 10000 A A 2013年 08月 09日 星期五 10:30:28 CST A 2013年 08月 09日 星期五 10:30:28 CST [root@centos192 ~]# ./count1.sh 99000 A A 2013年 08月 09日 星期五 10:30:43 CST A 2013年 08月 09日 星期五 10:30:45 CST
目前位置一切安好。现在我们在后台运行这个脚本,然后使用top命令来查看其CPU占有情况。
Tasks: 188 total, 2 running, 186 sleeping, 0 stopped, 0 zombie Cpu(s): 23.8%us, 1.2%sy, 0.0%ni, 74.8%id, 0.1%wa, 0.0%hi, 0.0%si, 0.0%st Mem: 3924872k total, 3438424k used, 486448k free, 529588k buffers Swap: 7574520k total, 0k used, 7574520k free, 1873432k cached PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 29561 root 20 0 105m 1096 728 R 99.6 0.0 1:06.54 bash 695 root 20 0 0 0 0 S 0.3 0.0 4:35.89 vmmemctl 29562 root 20 0 15024 1388 1008 R 0.3 0.0 0:00.13 top 1 root 20 0 19228 1532 1248 S 0.0 0.0 0:11.67 init 2 root 20 0 0 0 0 S 0.0 0.0 0:00.00 kthreadd
可以看出,我们的脚本使用了一个CPU的99.6的资源,如果想占用其他的CPU,则再运行上面的命令即可。如果脚本持续运行,那么将会严重影响系统的其他工作。
既然我们能够持续保持一个CPU处于繁忙状态,我们来看看如何设置一个进程的优先级。总结一下到目前为止我们学到的知识:
nice除了可以显示默认优先级外,还可以用来按照指定的优先级启动一个进程。你可以使用-n(或者--adjustment)选项接一个正数来增加优先级值,接一个负数来减少优先级值。一定要记住优先级值越大,优先级越低。通常只有root用户才能指定负值,也就是说普通用户只能让进程优先级降低而不能提升。
为了演示使用nice设置优先级,我们使用相同的脚本启动两个进程,其中一个进程的优先级为19,另一个默认。一秒以后使用ps-l 来显示进程状态,包括优先级。最后我们增加了一个30秒的睡眠来保证在子sh运行完之后才退出命令。如下图所示:
[root@centos192 ~]# (sh count1.sh 2000000 A&);(nice -n 19 sh count1.sh 2000000 B&);sleep 1; ps -l; sleep 30 A 2013年 08月 09日 星期五 12:29:10 CST B 2013年 08月 09日 星期五 12:29:10 CST F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD 4 S 0 29538 29536 0 80 0 - 27074 wait pts/2 00:00:00 bash 0 R 0 30573 1 99 80 0 - 26514 - pts/2 00:00:01 sh 0 R 0 30575 1 99 99 19 - 26514 - pts/2 00:00:00 sh 4 R 0 30579 29538 0 80 0 - 27030 - pts/2 00:00:00 ps B 2013年 08月 09日 星期五 12:29:39 CST A 2013年 08月 09日 星期五 12:29:40 CST
可能你会感到奇怪,这两个子进程几乎同时运行完毕。我们设置的优先级没有作用吗?请记住我们的脚本只使用一个CPU。此次运行的机器配备的是4核心的CPU。这样两2个子进程分别运行在不同的CPU核心上,也许没有必要让谁优先了。为了占满4个CPU核心,我们这次同时运行6个进程,优先级分别是0,4,8,12,16,19。
[root@centos192 ~]# (sh count1.sh 5000000 A&);(nice -n 4 sh count1.sh 5000000 B&);(nice -n 8 sh count1.sh 5000000 C&);(nice -n 12 sh count1.sh 5000000 D&);(nice -n 16 sh count1.sh 5000000 E&);(nice -n 19 sh count1.sh 5000000 F&);sleep 1; ps -l; sleep 30; A 2013年 08月 09日 星期五 12:25:05 CST B 2013年 08月 09日 星期五 12:25:05 CST C 2013年 08月 09日 星期五 12:25:05 CST D 2013年 08月 09日 星期五 12:25:05 CST E 2013年 08月 09日 星期五 12:25:05 CST F 2013年 08月 09日 星期五 12:25:05 CST F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD 4 S 0 29538 29536 0 80 0 - 27074 wait pts/2 00:00:00 bash 0 R 0 30471 1 50 80 0 - 26514 - pts/2 00:00:01 sh 0 R 0 30473 1 50 84 4 - 26514 - pts/2 00:00:01 sh 0 R 0 30475 1 49 88 8 - 26514 - pts/2 00:00:00 sh 0 R 0 30477 1 30 92 12 - 26514 - pts/2 00:00:00 sh 0 R 0 30480 1 12 96 16 - 26514 - pts/2 00:00:00 sh 0 R 0 30484 1 6 99 19 - 26514 - pts/2 00:00:00 sh 4 R 0 30489 29538 0 80 0 - 27029 - pts/2 00:00:00 ps C 2013年 08月 09日 星期五 12:26:19 CST A 2013年 08月 09日 星期五 12:26:19 CST B 2013年 08月 09日 星期五 12:26:20 CST D 2013年 08月 09日 星期五 12:26:49 CST E 2013年 08月 09日 星期五 12:27:15 CST F 2013年 08月 09日 星期五 12:27:25 CST
可以看出,如此一来就会出现多个进程使用竞争CPU的情况了,基本上优先级越高,那么被执行的机会就越多,执行完毕使用的时间就越少。
最后提醒大家,如同nohup命令一样,nice命令不能使用命令列表或者管线作为参数。
如果你已经启动了一个进程,之后又意识到需要改变这个进程的优先级,那么就可以使用renice命令。renice指定的是绝对优先级值而不是调整量。
i[root@centos192 ~]# sh count1.sh 10000000 A& [1] 30799 [root@centos192 ~]# A 2013年 08月 09日 星期五 12:43:19 CST [root@centos192 ~]# renice 1 30799; ps -l 30799 30799: old priority 0, new priority 1 F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD 0 R 0 30799 29538 97 81 1 - 26514 - pts/2 0:21 sh count1.sh 10000000 A [root@centos192 ~]# renice +3 30799; ps -l 30799 30799: old priority 1, new priority 3 F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD 0 R 0 30799 29538 98 83 3 - 26514 - pts/2 0:40 sh count1.sh 10000000 A
注意,只有root用户才能提高进程的调度优先级,让进程变得不太nice。更多信息参考nice和renice的man手册页。