為什么應(yīng)該在Linux上使用命名管道
命名管道并不常用,但是它們?yōu)檫M(jìn)程間通訊提供了一些有趣的特性。
估計(jì)每一位 Linux 使用者都熟悉使用 “|” 符號(hào)將數(shù)據(jù)從一個(gè)進(jìn)程傳輸?shù)搅硪粋€(gè)進(jìn)程的操作。它使用戶能簡(jiǎn)便地從一個(gè)命令輸出數(shù)據(jù)到另一個(gè)命令,并篩選出想要的數(shù)據(jù)而無須寫腳本進(jìn)行選擇、重新格式化等操作。
還有另一種管道, 雖然也叫“管道”這個(gè)名字卻有著非常不同的性質(zhì)。即您可能尚未使用甚至尚未知曉的——命名管道。
普通管道與命名管道的一個(gè)主要區(qū)別就是命名管道是以文件形式實(shí)實(shí)在在地存在于文件系統(tǒng)中的,沒錯(cuò),它們表現(xiàn)出來就是文件。但是與其它文件不同的是,命名管道文件似乎從來沒有文件內(nèi)容。即使用戶往命名管道中寫入大量數(shù)據(jù),該文件看起來還是空的。
如何在 Linux 上創(chuàng)建命名管道
在我們研究這些空空如也的命名管道之前,先追根溯源來看看命名管道是如何被創(chuàng)建的。您應(yīng)該使用名為 mkfifo
的命令來創(chuàng)建它們。為什么提及“FIFO”?是因?yàn)槊艿酪脖徽J(rèn)為是一種 FIFO 特殊文件。術(shù)語 “FIFO” 指的是它的先進(jìn)先出特性。如果你將冰淇淋盛放到碟子中,然后可以品嘗它,那么你執(zhí)行的就是一個(gè)LIFO(后進(jìn)先出操作。如果你通過吸管喝奶昔,那你就在執(zhí)行一個(gè) FIFO 操作。好,接下來是一個(gè)創(chuàng)建命名管道的例子。
$ mkfifo mypipe
$ ls -l mypipe
prw-r-----. 1 shs staff 0 Jan 31 13:59 mypipe
注意一下特殊的文件類型標(biāo)記 “p” 以及該文件大小為 0。您可以將重定向數(shù)據(jù)寫入命名管道文件,而文件大小依然為 0。
$ echo "Can you read this?" > mypipe
正如上面所說,敲擊回車后似乎什么都沒有發(fā)生(LCTT 譯注:沒有返回命令行提示符)。
另外再開一個(gè)終端,查看該命名管道的大小,依舊是 0:
$ ls -l mypipe
prw-r-----. 1 shs staff 0 Jan 31 13:59 mypipe
也許這有違直覺,用戶輸入的文本已經(jīng)進(jìn)入該命名管道,而你仍然卡在輸入端。你或者其他人應(yīng)該等在輸出端,并準(zhǔn)備讀取放入管道的數(shù)據(jù)。現(xiàn)在讓我們讀取看看。
$ cat mypipe
Can you read this?
一旦被讀取之后,管道中的內(nèi)容就沒有了。
另一種研究命名管道如何工作的方式是通過將放入數(shù)據(jù)的操作置入后臺(tái)來執(zhí)行兩個(gè)操作(將數(shù)據(jù)放入管道,而在另外一段讀取它)。
$ echo "Can you read this?" > mypipe &
[1] 79302
$ cat mypipe
Can you read this?
[1]+ Done echo "Can you read this?" > mypipe
一旦管道被讀取或“耗干”,該管道就清空了,盡管我們還能看見它并再次使用??蔀槭裁匆M(fèi)此周折呢?
為何要使用命名管道?
命名管道很少被使用的理由似乎很充分。畢竟在 Unix 系統(tǒng)上,總有多種不同的方式完成同樣的操作。有多種方式寫文件、讀文件、清空文件,盡管命名管道比它們來得更高效。
值得注意的是,命名管道的內(nèi)容駐留在內(nèi)存中而不是被寫到硬盤上。數(shù)據(jù)內(nèi)容只有在輸入輸出端都打開時(shí)才會(huì)傳送。用戶可以在管道的輸出端打開之前向管道多次寫入。通過使用命名管道,用戶可以創(chuàng)建一個(gè)進(jìn)程寫入管道并且另外一個(gè)進(jìn)程讀取管道的流程,而不用關(guān)心協(xié)調(diào)二者時(shí)間上的同步。
用戶可以創(chuàng)建一個(gè)單純等待數(shù)據(jù)出現(xiàn)在管道輸出端的進(jìn)程,并在拿到輸出數(shù)據(jù)后對(duì)其進(jìn)行操作。下列命令我們采用 tail
來等待數(shù)據(jù)出現(xiàn)。
$ tail -f mypipe
一旦供給管道數(shù)據(jù)的進(jìn)程結(jié)束了,我們就可以看到一些輸出。
$ tail -f mypipe
Uranus replicated to WCDC7
Saturn replicated to WCDC8
Pluto replicated to WCDC9
Server replication operation completed
如果研究一下向命名管道寫入的進(jìn)程,用戶也許會(huì)驚訝于它的資源消耗之少。在下面的 ps
命令輸出中,唯一顯著的資源消耗是虛擬內(nèi)存(VSZ 那一列)。
ps u -P 80038
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
shs 80038 0.0 0.0 108488 764 pts/4 S 15:25 0:00 -bash
命名管道與 Unix/Linux 系統(tǒng)上更常用的管道相比足以不同到擁有另一個(gè)名號(hào),但是“管道”確實(shí)能反映出它們?nèi)绾卧谶M(jìn)程間傳送數(shù)據(jù)的形象,故將稱其為“命名管道”還真是恰如其分。也許您在執(zhí)行操作時(shí)就能從這個(gè)聰明的 Unix/Linux 特性中獲益匪淺呢。