融于心而表于行 之 程序的执行问题
2.4 程序的執行問題
Linux的多用戶說完了,還需要進行下一個話題,那就是多任務的問題。所謂多任務,就是同一時刻能夠執行多個程序。這個問題其實對于大多數Windows用戶它都不是個問題,因為我們經常會一邊瀏覽網頁,一邊用QQ聊天,同時還能聽音樂。因為Windows可以在將這些軟件的界面同是展現在屏幕上,即便放不下,也可以通過“窗口”堆疊的方式堆起來。要用哪個就將哪個放到最上面好了。Linux在使用圖形環境下的時候也是這樣,所以沒有什么要專門拿它來說一說的必要。但是在命令行下這就真是一個問題了。比如你知道如何在命令行下同時運行多個程序嗎?同時開幾個終端的做法您就別耍這個小聰明了,因為那個不算。接下來我們就要看看Linux是怎么解決這個問題的。
2.4.1 執行程序的方法
如果只是簡單的在命令行上執行一個程序則是一個非常簡單的問題,基本上有一些計算機常識的人都應該能夠猜到,直接輸入程序的名稱就能執行程序。沒錯,Linux就是這樣設計的,而且我們之前執行的那些命令,絕大多數都是具體的程序,而命令名也就是具體的程序名。如果你根據這個經驗,當你要執行當前你所在的目錄下的一個可執行文件時,可能會不假思索的直接輸入程序名以期望它的執行,因為Windows就是這樣設計的。但是,在Linux你可能會收獲失敗,因為Linux與Windows的設計是不同的。當我們直接在命令行下輸入命令之后,Linux系統只會在$PATH環境變量所指定的那些路徑中搜索對應的程序(Windows會先搜索一下當前目錄,再搜索$PATH所指定的目錄),如果找不到就失敗。如果要執行不在$PATH所指定的路徑中的程序,必須使用相對路徑或絕對路徑。所以,即便是在當前路徑下的一個程序文件,比如abc.exe,則需要使用./abc.exe。根據使用Windows的習慣,執行型文件的擴展名是可以忽略的,但是Linux根本不需要擴展名來決定文件的可執行性,所以也不能忽略所謂的擴展名。
但是像我們前面給出的cpio程序執行的例子又是我們遇到的一個新問題,因為它的形式比較古怪。比如我們要將/boot目錄下的所有文件打包成一個文件,我們可以執行這樣的命令:
$ find /boot | cpio -ocB > /tmp/boot.img
這條命令一共包含了兩個不同的命令程序——find和cpio。那是不是這兩個命令程序會同時執行呢?答案是肯定的。這就體現出Linux系統多任務的特性了,而且還體現出Linux系統多任務可協調的特性,即多個任務之間是能夠互幫互助的。兩個命令之間的豎線“|”就是起這種協調作用的,比較專業的稱呼叫“管道符”,而這種程序直接的協調技術也被稱之為“管道”,更為專業的名稱叫“匿名管道”。
管道是Linux系統提供的多任務協調機制的一種,應用十分廣泛。管道可分為匿名和命名兩種,但是不管怎樣它們都擁有一個共同的特性,就是數據只能從管道的一端寫入并從另一端讀取,而且讀出的順序與寫入的順序是相同的。所以管道也叫做FIFO(First Input First Output)。那么匿名和命名管道有什么區別呢?其實就是臨時工和正式工的差別。所謂匿名就是不記名,隨用隨叫,屬于臨時工;而命名的則需要分配固定的資源,有固定的崗位和編制,不管你用還是不用它都得在那兒,除非你將它除名才行,所以是正式工。就我們前面的例子,使用豎線“|”建立的管道就是匿名的臨時工,而要建立命名管道則需要使用mkfifo命令,它會在我們指定的路徑上創建一個文件類型為“p”的文件。其實這年頭正式工是越來越少的,很多事情都是臨時工干的,Linux這點還是非常與時俱進的。
我們再回到前面列舉的例子,find命令處于管道的寫入端,cpio命令處于管道的讀取端。通過單獨執行“find /boot”命令我們可以了解它將/boot目錄下的所有文件都顯示在屏幕上了。在本例中,這些原本要輸出到屏幕上的內容不見了。去了那里了呢?管道里。然后“流到”了cpio內部,并被統統打包壓縮到了/tmp/boot.img文件中。但是這就更讓人糊涂了,怎么好端端的往屏幕上輸出的內容跑到管道里去了呢?這就引出了Linux中的另外一項技術——I/O重定向。
I/O重定向也是Linux提供的一種多任務協調機制。所以的I/O沖定向,就是把輸出給A的東西重定向給了B,或者反過來說將要從A處獲得的輸入重定向到B處去獲得了。在我們的例子中正反兩種重定向都應用了,而且還應用了隱式重定向和顯示重定向兩種方式。隱式重定向發生在“匿名管道”處,find命令將輸出給屏幕的東西重定向給了管道寫入端,而cpio命令要從鍵盤獲得的輸入重定向到了管道讀出端。這樣,find和cpio就建立數據通路,find查詢出來的文件名源源不斷的送給cpio來處理并將對應的文件打包起來。而在cpio處應用了一個顯示的重定向,就是右尖括號“>”,它顯示的指明將命令輸出到屏幕的內容重定向到磁盤文件中。我們的例子就是將cpio的輸出內容重定向到/tmp/boot.img文件中保存起來。順便說一句,由于命名管道也是創建了具體的文件,所以使用命名管道時對其讀寫應該使用顯示的I/O重定向。
通過上述內容的介紹,大家是否已經有所察覺,在這個例子中find和cpio就像流水線一樣在加工數據。其實我們如果愿意,還能夠在這條流水線上繼續增加元素。比如我們要對cpio打包的文件還要進行壓縮,可以執行這樣的命令:
$ find /boot | cpio -ocB | gzip -9 >/tmp/boot.img
這就會有三個命令程序一同運行了,并且數據從find開始,流過cpio打包,流過gzip進行壓縮,最后流向/tmp/boot.img文件。整體猶如行云流水連綿不絕。所以這種程序執行方式也有一個十分貼切的名字——流式處理。
還有一個重定向符是左尖括號“<”,它顯示的指明將一個文件的內容重定向到鍵盤輸入中。那么對于cpio命令來講,在做解包的時候,應該這樣操作:
$ gzip-dc /tmp/boot.img | cpio -idc
Linux上的大多數程序都支持這種流式處理,而且這種流式處理可以讓若干簡單的命令結合起來去完成很多讓人無法想象的復雜任務。這也正是Linux迷人的地方所在,到處都是“只有你想不到沒有它做不到”。而且要想你的程序也支持這種流式處理也是非常簡單的,只要從鍵盤獲得輸入,然后將結果輸出到屏幕上就基本可以滿足要求了。更為具體的,本書后續章節還會有詳細論述。
雖然流式處理可以允許多個程序一同執行,但是這些都是一些相關聯的程序。如果我要同時執行一些不相關的程序,而且還希望像在圖形界面中那樣能夠來回切換該怎么處理呢?這就要涉及到了前后臺任務了。
所謂前臺任務就是當前與我們交互的程序,而后臺任務就雖然執行著但是不與我們交互的程序。與圖形界面不同,在命令行下,前臺任務是我們唯一可見的任務。后臺任務要想成為前臺任務,必須先當前的前臺任務切換成后臺任務。把當前任務切換成后臺任務需要使用快捷鍵“Ctrl+Z”。比如執行命令:
$ tail -f /etc/profile
之后,按下快捷鍵“Ctrl+Z”,就會看到輸出這樣的內容:
[1]+ Stopped tail-f /etc/profile
然后執行命令:
$ bg
[1]+ tail -f /etc/profile &
這就代表我們已經將剛才創建的前臺任務切換到后臺了。而我們想直接創建一個后臺任務,也可以直接在命令末尾添加“&”符號來完成,例如:
$ tail -f /etc/bashrc &
[2] 29732
……
然后輕輕回車,就可以繼續做其他的事情了。經過上述的兩個過程,我們已經創建了兩個后臺任務。如果要查看這些任務,可以使用jobs命令,例如:
$ jobs
[1]- Running tail -f /etc/profile&
[2]+ Running tail -f /etc/bashrc &
注意前面的[1]、[2]這些數字,這是是任務號,要想將某個后臺任務切換到前臺,就用利用這個任務號了。切換命令是fg。例如:
$ fg 1
tail -f /etc/profile
這樣,“tail -f /etc/profile”就被切換到前臺了。還有注意任務號后面的那個“+”和“-”。帶有“+”的任務屬于默認任務,即執行不帶任何參數執行fg命令時切換到前臺的任務。
對于如何結束一個處于前臺的程序恐怕大家都不陌生。要么等它執行完畢,要么就按“Ctrl+C”干掉它。但是對于被切換到后臺的程序“Ctrl+C”可就不管用了,難道我們要結束這樣的程序就只能等它自己執行完畢或者切換到前臺嗎?不是,Linux下還有第三種選擇,就是使用kill命令干掉它。比如我要干掉2號任務,可以這樣操作:
$ kill -9 %2
$ jobs
[1]- Running tail -f /etc/profile&
[2]+ Killed tail -f /etc/bashrc&
需要注意,kill命令是傳遞信號給具體的任務或進程,-9就是一個信號。這個信號相當霸道,會強制干掉一個不正常的任務或進程。而kill默認發出的信號實際上是-15,這個信號會使得程序正常退出。至于有關信號方面的信息,本書后面的內容還會有詳細介紹,等不及的人可以執行“man 7 signal”命令提前學習。另外,kill最后面的那個參數實際上是傳遞一個數字的進程ID,但是這與任務號有沖突,所以要加上%來加以區分。
剛才說的是要干掉某個任務,但是還有一個十分棘手的問題就是不希望任務被無故干掉。任務在什么情況下會被無故干掉呢?你退出終端的時候就會。因為Linux下任務是與操作者終端關聯的,只要你退出了終端,與其關聯的所有任務都會被干掉。但是有些時候你又不能總是守在終端前,還不想任務被干掉,怎么辦呢?使用nohup命令,它能保證被他啟動的任務脫離與終端的關聯。一般的用法是:
$ nohup [命令與參數] &
需要注意,這樣命令的所有輸出都會輸出到nohup.out這個文件中,但是這個任務就不再與你的終端有什么聯系了。放心的關掉終端回家陪老婆去吧!
上述的過程就基本梳理出了Linux進行多任務使用和切換的方法,雖然要比Windows等圖形界面上的體驗要差很多,但是在執行少量任務的時候還是比較方便的,畢竟Linux的設計目的不是讓你來回切換任務玩的。它是從正面鼓勵你使用流式方式執行程序的,所以要很好的掌握管道和I/O重定向的技巧。
2.4.2計劃任務
使用計劃任務是在Linux下執行程序的另外一種方式,分為一次性的和周期性的兩類。
執行一次性的計劃任務需要使用at命令。每次執行at命令需要給他傳遞一個時間參數,來指明計劃任務執行的時間。比如:
$ at 10:00 tomorrow
這條命令要求明天上午10點整執行一個程序。那么怎么設定具體要執行什么程序呢?要知道答案就地繼續往下看。就在執行at命令之后,命令行會變成這樣:
at>
只要直接輸入想執行的命令即可,比如echo "hello world"。輸入完命令之后,按組合鍵Ctrl+D來保存。然后就會立即顯示類似這樣的內容:
job 1 at 2012-12-20 10:00
這說明“job 1”將在2012年12月20日的10點整執行。這樣,你就成功的創建了一個一次性任務。需要注意,我們在列舉這個例子的時候有些偷懶,主要是echo這個命令我們沒有提供全路徑。這并不是不對,而是不很規范。因為直接使用名稱來執行程序能夠成功的根本是因為有PATH環境變量。如果PATH環境變量沒有設定,那么所有直接使用名稱執行的程序都會失敗。雖然我們平時很難遇到PATH環境變量沒有被設置的情況,但是在計劃性任務中確很常見,所以使用全路徑來執行計劃任務是非常良好的習慣。為此,我們的例子應該改成“/bin/echo "hello world"”,這樣雖然看起來不是很美觀,但是總是能夠保證它被執行成功。而且每個計劃任務也不是只能執行一個程序,也可以是一個按行劃分的程序列表,待執行任務時,按程序出現的次序依次執行。
不知道你是否注意到,at命令在接受完輸入的時候使用了比較有特點的Ctrl+D命令來保存內容。在Linux中Ctrl+D代表EOF,說明已經輸入完畢。但是這種EOF僅對直接從鍵盤中獲得輸入的情況下有效,即輸入Ctrl+D之后,代表從鍵盤中獲得的輸入完畢了。所有的這種從標準輸入獲取輸入數據的程序都可以使用類似方法輸入數據。但是這種錄入數據的方法有一個缺點,就是一旦中間有錯誤,就只能全部重來。為了彌補這個缺點,可以使用I/O重定向將一個文件中的內容輸入給它,我們要做的就是編輯好那個文件的內容。就比如這個例子,我們可以先創建一個包含命令的文件然后我們就可以使用“<”操作符將文件的內容傳給它,并稱為一個新的計劃任務,而且你再也不會看到“at>”這樣的提示符了。
一般一次性計劃任務是很少應用的,大多都是周期性計劃任務。這也就時很多人都會聽過大名鼎鼎的cron,而很少了解at的根本原因。
使用cron都是通過crontab命令來完成的。“crontab –e”來編輯當前用戶的cron表;“crontab -l”查看當前用戶的cron表;“crontab –r”刪除當前用戶的cron進程;“crontab -u 用戶名”以某用戶的身份來控制cron表。這些基本上就是操縱cron的全部了。
為了創建一個周期性任務,需要使用“crontab –e”命令來打開cron表。這個命令會啟動vi程序來編輯cron表,具體如何使用vi,本書后面會有專門的章節來介紹,目前只需要按一下“i”鍵進入編輯模式即可。
一個cron任務在cron表用一行來表示。每一行被分為兩列,左邊是時間,右邊是具體運行的命令,與at相同,盡量使用命令的全路經。時間是由5個部分組成,每部分用空客隔開,分別代表:
l每小時的第幾分鐘:0~59;
l每天的第幾小時:0~23;
l每月的第幾天:0~31;
l每年的第幾月:1~12;
l每周的星期幾:0~6,0表示星期日。
此外,在時間和命令之間,還有一個可選的用戶名,用來說明cron以何種用戶身份來執行命令。因此,一個cron任務的完整定義應該是:
分鐘小時日月周 [用戶名] 命令
如果要設定在我太太生日那天,每到整點就提醒我買禮物,那么可以在cron表中添加如下一條:
0 * 1 8 * echo "老婆大人的生日,要買禮物。"
然后按“ESC”鍵退出到命令模式,輸入“:wq”,退出并保存。這樣,每到8月1日,整點就會提醒我。但是,我突然發現整點提醒我有點太寬泛了,甚至0點就開始提醒我。這有些不妥,干脆做了一下修改:
0,15,30,45 12 1 8 * echo "老婆大人生日,要買禮物。"
這樣,只有8月1日的中午12點,每隔15分鐘,會提醒我一次。這個設定顯然不錯,但是對于有代碼潔癖的我來講,還需要改進一下:
*/15 12 1 8 * echo "老婆大人生日,要買禮物。"
作用沒變,顯然簡潔了一些,我很滿意。
通過上面的這些內容,可以比較直觀地看出,cron表中的時間設定擁有極高的靈活性,使得設定周期任務非常方便。每一個時間參數可以有幾種符號表示,如表2-1所示:
表2-1cron時間符號
符號 | 含義 |
* | 代表任意時間 |
, | 代表分隔出不連續的時間點,比如2,3表示2和3都行 |
- | 代表連續的時間段,比如2-4表示2、3、4 |
*/n | 表示每隔單位時間 |
雖然計劃任務有時非常有用,但是也不是所有用戶都能添加的,具體誰能添加計劃任務,主要有系統中這四個文件來決定:at.allow、at.deny、cron.allow和cron.deny。其實不用解釋也能猜到,以at開頭的管at,以cron開頭的管cron。而且這些文件是有互斥性的,即allow的deny不會同時存在。allow也叫白名單,deny也叫黑名單,所以在allow中的用戶就允許指定計劃任務,在deny中的用戶就不允許指定計劃任務。當前的大多數Linux發行版使用黑名單機制,對計劃任務權限的管理相對很寬松。
2.4.3 守護進程
計劃任務基本上就算介紹完了,還有什么不明白的就找那個“男”的問吧。那么接下來就要看看計劃任務是怎么被執行的了,這主要歸功于守護進程。
Linux服務器在啟動時需要啟動很多系統服務(其實Windows也這樣),它們向本地或網絡用戶提供了Linux的系統功能接口,直接面向應用程序和用戶。提供這些服務的程序是由運行在后臺的守護進程(daemons)來執行的。
守護進程是生存期很長的一種進程。它們獨立于控制終端并且周期性地執行某種任務或等待處理某些發生的事件。它們常常伴隨著Linux系統啟動時啟動,關閉時關閉。linux系統有很多守護進程,大多數服務器都是用守護進程實現的。另外,某些守護進程還協助完成了很多系統任務,比如負責計劃任務的atd和crond、負責打印的lqd等。
有些資料也把守護進程稱作:“服務”,但嚴格意義上來講還是有一些不同的,只是一般我們不用去強調它們的異同。如果一定要分出個是非來,那么“服務”是靜態的概念,而守護進程是動態的概念。服務由守護進程提供。選擇運行哪些守護進程,要根據具體需求來決定。查看系統中擁有哪些守護進程,或者說能夠提供哪些服務,可以使用ntsysv命令(在RedHat或Cent OS中)。要成功執行這個命令,需要使用root權限。
實際上守護進程也是有分類的,可以按照它的啟動和管理方式來區分,分為獨立啟動的stand alone和xinetd兩類。
所謂的stand alone,從字面上的意思來看就是“獨立”的含義。這種類型的守護進程有兩大特點,一是可以自行啟動運行而不需要利用系統其他機制來管理,二是啟動之后會一直占用內存與系統資源。因而這種守護進程擁有了一個非常突出的有點:響應最快。stand alone守護進程非常多,常見的apache、mysql等都是。
至于xinetd是一種比較新型的守護進程。它由一個統一的stand alone守護進程來負責喚起。這個特殊的守護進程還有一個好聽的名字——superdaemon。之所以會引入這種機制,就是因為stand alone會一直占用內存和資源會顯得很浪費。所以一些喜歡精打細算的人就提出來按需分配這種概念。也就是說,當沒有客戶端要求的時候,xinetd類型的守護進程都是未啟動,待有客戶端要求服務是,super daemon才會去喚醒具體的xinetd守護進程。但是這種按需分配的機制的致命缺點就是不能及時響應。但是優點也非常鮮明。其一,由于super daemon負責喚醒各項服務,因此可以賦予super daemon安全管控的機制,這就類似網絡防火墻的功能了;其二,也是它的設計初衷,即客戶端的聯機結束后就關閉不會一直占用系統資源。
大多數Linux發行版會將所有stand alone守護進程的啟動腳本都放置在/etc/init.d/目錄下,這是一個公認的目錄。而Cent OS實際上是放在了/etc/rc.d/init.d/目錄下了,而/etc/init.d只是它的一個符號連接。大家在記憶的時候,只要記住公認目錄即可,那些發行版自己耍的小聰明就不要理會了。
直接執行某個stand alone守護進程的啟動腳本會顯示這個啟動腳本的用法,比如“/etc/init.d/atd”這個腳本,會有這樣的用法提示:
Usage: atd{start|stop|status|restart|condrestart|try-restart|reload|force-reload}
其中start、stop和restart這三個命令選項是最通用的,幾乎所有stand alone守護進程的啟動腳本支持,分別代表啟動、停止和重啟。
xinetd守護進程的配置文件放置在/etc/xinetd.d/目錄下和/etc/xinetd.conf文件。一般不用關心xinetd.conf文件的內容。而/etc/xinetd.d中的每個文件代表一個獨立的xinetd守護進程。比如rsync的配置內容如下所示:
# default: off
# description: The rsync server isa good addition to an ftp server, as it \
#allows crc checksumming etc.
service rsync
{
disable = yes
flags = IPv6
socket_type = stream
wait = no
user = root
server = /usr/bin/rsync
server_args = --daemon
log_on_failure += USERID
}
其中“disable=yes”代表該守護進程處于關閉狀態。如果要開啟rsync服務,只要改成“disable=no”即可。然后執行/etc/init.d/xinetd restart重啟super daemon。這樣,當有客戶端請求rsync服務的時候,xinietd守護進程就會啟動/usr/bin/rsync程序來提供服務。
雖然我們知道了如何開啟一個xinetd守護進程,但是當客戶請求rsync服務的時候,xinetd怎么就知道啟動/usr/bin/rsync這個程序呢?答案在/etc/services文件中,在這個文件中我們會找到類似這樣的內容:
……
rsync 873/tcp #rsync
rsync 873/udp #rsync
……
因為rsync對外提供服務的端口是873,而xinetd也會監聽這個端口,當發現有客戶端連接到這個端口上,根據/etc/services文件就了解到是rsync服務。然后根據/etc/xinetd.d/rsync文件中的內容判斷是開啟狀態,于是啟動服務。
2.4.4 程序信息
到目前為止,Linux下如何執行程序,程序都有那些存在形式都已經介紹完了,但是這些內容對于一個擁有多任務功能的系統還遠遠不夠,還應該讓用戶能夠了解到當前系統中運行著那些程序、都使用了哪些資源以及程序之間的關系是什么。ps、top和pstree這三個命令正好提供了這些功能。
ps命令主要是查看程序的靜態信息,即將某個時間的程序運行情況擷取下來。比較常用的用法有:“ps aux”查看系統中所有程序的數據;“psux”查看當前用戶所有程序的數據;“ps –l”查看與當前終端關聯的程序數據。注意,有的有“-”,有的沒有“-”。由于ps的man page非常復雜,所以大家只要記住我們提供的這三個常用用法基本上就能滿足日常工作了。
對于“ps -l”命令,在我們的機器中執行的結果如下所示:
F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD
0 S 500 2570 2569 0 80 0 - 27134 wait pts/1 00:00:00 bash
0 R 500 10716 2570 0 80 0 - 26487 - pts/1 00:00:00 ps
這些字段的定義見表2-2所示:
表2-2“ps -l”命令輸出的各字段說明
字段 | 說明 |
F | 程序標志,代表程序的執行權限,常見的取值有:0,普通權限;4,root權限;1,此程序僅執行了fork而沒有執行exec |
S | 程序狀態:R,運行中;S,睡眠狀態,可喚醒;D,不可被喚醒狀態,一般是在等待I/O;T,停止狀態,比如被調試的時候;Z,僵尸狀態,程序已經終止但卻無法被移除至內存外 |
UID | 此進程擁有者的UID |
PID | 此進程的進程ID |
PPID | 此進程的父進程ID |
C | CPU的使用率,單位為百分比 |
PRI | 運行優先級 |
NI | 運行優先級調整值 |
ADDR | 指出該程序在內存的哪個部分,如果是個 running 的程序,一般就會顯示“-” |
SZ | 此程序用掉的內存 |
WCHAN | 表示目前程序是否運行中,若為“-”表示正在運行中 |
TTY | 登陸者的終端機位置,若為遠程登陸則使用動態終端介面 |
TIME | 使用掉的CPU時間,注意,是此程序實際花費 CPU 運行的時間,而不是系統時間 |
CMD | 就是command的縮寫,也就是程序名稱 |
雖然對照上表理解“ps -l”命令的輸出不是什么難事,但是千萬別以為這些就是全部了,因為“psaux”命令的輸出還不太一樣,具體可參考如下所示:
這下傻眼了吧?兩個命令的輸出內容有點不一樣,所幸就再列一個表吧,見表2-3所示:
表2-3“ps aux”命令輸出的各字段說明
字段 | 說明 |
USER | 該進程所屬的使用者用戶名 |
PID | 該進程的進程ID |
%CPU | 該進程所占CPU資源的百分比 |
%MEM | 該進程所占實體內存的百分比 |
VSZ | 該進程用掉的虛擬內存量(kbytes) |
RSS | 該進程占用的固定的內存量(kbytes) |
TTY | 該進程所運行的終端機,若與終端機無關則顯示“?”。另外,tty1-tty6 是本機上面的登陸者程序,若為pts/0等等的,則表示為由網絡連接進主機的程序 |
STAT | 該進程的當前狀態,與“ps –l”的S字段相同(R/S/T/Z) |
START | 進程啟動時間 |
TIME | 該進程使用CPU運行的時間 |
COMMAND | 改程序的實際命令 |
有些時候“ps aux”命令輸出的COMMAND字段會非常長,以至于被終端屏幕截斷。解決這個問題的方法是使用more命令,就是這樣使用:
$ ps aux | more
如果輸出內容一屏無法顯示完畢,more命令會在屏幕滿是停止輸出。按回車(enter)鍵,可以繼續查看更多的內容,要退出可以按“Q”鍵。
給ps傳遞不同的參數會產生不同的輸出結果顯然是比較坑人的設計,但是這也是ps強大的體現。因為這樣設計,可以使得ps命令很容易的與Linux系統中的其他命令結合使用(利用管道和I/O重定向),來實現更為復雜的程序信息觀測程序。但也正因為ps要滿足這樣的需求,使得它存在一定的局限性,那就是只能擷取某一個時間點的程序狀態。如果期望動態監測系統中程序的運行狀態,可以使用top命令。順便提一句,使用ps命令和Linux中的其它工具相結合,也能夠實現類似top的功能。至于如何實現,相信讀完本書的人應該能夠自行完成。
top命令輸出非常豐富,而且每隔5秒鐘就會刷新一次。如下所示展示了top命令的大部分輸出內容:
總體來看,top命令的輸出共分為兩個部分。上面的部分展示的是整個系統的資源的使用狀態,而下面的部分展示的則是單個進程的資源使用情況。
top使用5行文本來描述整個系統的資源使用狀態,顯示的內容依次是:
l第一行:top - 當前時間 up 系統連續運行時間,已登錄系統的用戶數(3 users),系統在1、5、15分鐘的平均工作負載(load average)。
l第二行:進程的總數、正在運行數、睡眠數、停止數和僵尸數。
l第三行:用戶空間占用CPU的百分比(%us)、內核空間占用CPU的百分比(%sy)、改變過優先級的進程占用CPU的百分比(%ni)、空閑CPU百分比(%id)、I/O等待專用CPU的百分比(%wa)、硬中斷占用CPU的百分比(%hi)、軟中斷占用CPU的百分比(%si)、被強制等待虛擬CPU的時間(%st,在虛擬系統中有效)。
l第四行:物理內存總數、已用數、空閑數、緩沖數。
l第五行:交換分區總數、已用數、空閑數、緩存數。
至于top所提供的單獨進程信息,與前面介紹的ps命令所提供的信息基本類似,這里不做復述。不太一樣的就是VIRT、RES和SHR這三個字段。它們分別代表虛擬內存用量(只是需要的,不是實際使用量)、常住內存量(實際使用量,包含共享部分)和共享內存。計算一個進程所占用的真實物理內存可以使用公式:RES-SHR來計算。
在top的上半部分輸出中的cpu占比部分,有些時候會出現超過100%的情況。其實這是非常正常的,因為top計算的CPU占比是按照單個CPU核心來計算的,如果一個計算機內有16個CPU核心,那么這個CPU占比最高可以達到1600%。
top命令所展示的數據當中最讓人迷惑的就是平均工作負載(load average)了。這是一個什么概念呢?我們可以做一個行車過橋的比喻。對于一個單核處理器,就好比是一條單車道。設想下,你現在需要收取這條道路的過橋費--忙于處理那些將要過橋的車輛。你首先當然需要了解些信息,例如車輛的載重、以及還有多少車輛正在等待過橋。如果前面沒有車輛在等待,那么你可以告訴后面的司機通過。如果車輛眾多,那么需要告知他們可能需要稍等一會。因此,需要些特定的代號表示目前的車流情況,例如:
l0.00,表示目前橋面上沒有任何的車流。實際上這種情況與0.00和1.00之間是相同的,總而言之很通暢,過往的車輛可以絲毫不用等待的通過。
l1.00,表示剛好是在這座橋的承受范圍內。這種情況不算糟糕,只是車流會有些堵,不過這種情況可能會造成交通越來越慢。
l超過1.00,那么說明這座橋已經超出負荷,交通嚴重的擁堵。那么情況有多糟糕?例如2.00的情況說明車流已經超出了橋所能承受的一倍,那么將有多余過橋一倍的車輛正在焦急的等待。3.00的話情況就更不妙了,說明這座橋基本上已經快承受不了,還有超出橋負載兩倍多的車輛正在等待。
由此可見,平均工作負載不能超過1.00,超過了就說明系統已經快要不堪重負了。但是很多人的實際經驗是經常看到查過1.00的情況。其中一種與CPU占比相同,與核心數量有關。如果是16核心的系統,平均工作負載可以達到16.00;而另外一種則是系統已經不堪重負了,雖然依然能夠運行,但這個只能從側面說明Linux系統的穩定性很好了。
top命令還有很多選項可用,其中比較重要的是“-d”選項,用來修改top刷新數據的頻率的。top命令還能單獨最終某個進程的運行狀態,方法就是使用“-p”選項,例如:
$ top -d 2 -p 12201
就是表明每兩秒刷新一次,只監控PID為12201的進程。top在運行中,也有一些按鍵可以操作,比如:P鍵,讓單個進程信息按照CPU使用率排序;M鍵,以內存的使用率排序;N鍵,以進程的PID排序;等等。
ps和top命令可以很方便的獲得單個進程的信息。如果要查看進程的父子祖先關系,雖然ps命令能夠滿足,但是最方便的應該是pstree了。至于是什么的效果,你直接操作一下就好了,畢竟浪費紙張是一件十分可恥的事情。
轉載于:https://blog.51cto.com/jagen/1309939
總結
以上是生活随笔為你收集整理的融于心而表于行 之 程序的执行问题的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: BJRangeSliderWithPro
- 下一篇: jQuery css