Shell 中利用FIFO實現多進程tar解壓的方法

上文Shell中使用tar命令批量解壓縮的實現方法中提到我使用循環的方法批量解壓tar文件,可是單進程的解壓耗時太長,須要優化,故決定採用FIFO(有名管道)實現可控併發數的多進程解壓。linux

須要直接知道解決方案的請看第二節

1.FIFO(有名管道)簡述

FIFO,又稱做命名管道(named pipe),它是Linux中用於進程間通訊的一種方法。 FIFO是一種特殊的文件。因爲linux全部的事物均可以被視爲文件,因此對命名管道的使用也就變得與文件操做很是統一。 FIFO簡單理解,就是它能把兩個不相關的進程聯繫起來,FIFO就像一個公共通道,解決了不一樣進程之間的「代溝」。普通的無名管道只能讓相關的進程進行溝通(好比父shell和子shell之間)。shell

下面模擬了一個FIFO通訊的過程,主要有兩個進程:

#!/bin/bash
#Client.sh
#不斷向fifo寫入數據

tmp_fifo="/tmp/test.fifo"
rm -f $tmp_fifo
mkfifo $tmp_fifo
exec 6<>$tmp_fifo #這句話能把管道變成非阻塞!

i=0
while :
do
	sleep 1                 # 1秒寫一次
	echo "$i" >&6
        echo "$i"    
        #輸出到終端的時候要當心,會覆蓋你的終端,因此要中止,最好直接掛起進程!!
	let i++
done 

exec 6>&-
複製代碼
#!/bin/bash
#Server.sh
#不斷從fifo中讀出數據

tmp_fifo="/tmp/test.fifo"
echo "$tmp_fifo"
exec 6<>$tmp_fifo                 #創建一個綁定

while :
do
        read TEXT
	sleep 1
	echo "$TEXT"          #每1s就讀取一個數據,而且打印到終端,要中止,最好掛起進程!
done <&6

複製代碼

打開終端A:$ ./Client.shbash

打開終端B:$./Server.sh併發

你就能看到在終端B中從fifo中讀取到的數據,你要是在終端B中把每次讀fifo的間隔給改爲2秒,就更能說明問題了。上面的程序,在實驗的時候最好經過不斷掛起A進程來查看,而後觀察B進程的輸出。你會知道FIFO整個是怎麼跑的。。。post

FIFO的出現,極好地解決了系統在應用過程當中產生的大量的中間臨時文件的問題。FIFO能夠被shell調用使數據從一個進程到另外一個進程,系統沒必要爲該中間通道去煩惱清理沒必要要的垃圾,或者去釋放該通道的資源,它能夠被留作後來的進程使用。而且規避了匿名管道在做用域的限制,可應用於不相關的進程之間。測試

此節參考文章:blog.csdn.net/firefoxbug/…優化

2.利用FIFO實現多進程tar解壓

#獲取類型(Http等),目錄地址,臨時方案
type=$1
dir=$2
#獲取時間,包括月、日、小時帳期
#測試使用-調度內採用Oracle導入時間參數 
v_month=`date -d "-1 month" '+%Y%m'` #當月
echo $v_month
v_day=`date '+%Y%m%d'` #當日
echo $v_day
#v_hour=`date -d "-1 hour" '+%Y%m%d%H'` #前一個小時
echo $v_hour

#建立臨時文件夾
temp='temp_'${type}'_'${v_hour}
echo ${temp}
mkdir ${dir}/${temp}

#聲明併發線程併發個數
THREAD=4
#聲明管道名稱,'$$'表示腳本當前運行的進程PID 
TMPFIFO=/tmp/$$.fifo
 #建立管道
mkfifo $TMPFIFO
#建立文件標示符「5」
#這個數字能夠爲除「0」、「1」、「2」以外的全部未聲明過的字符,以讀寫模式操做管道文件
#系統調用exec是以新的進程去代替原來的進程,但進程的PID保持不變
#換句話說就是在調用進程內部執行一個可執行文件 
exec 5<>${TMPFIFO}
#清除建立的管道文件 
rm -rf ${TMPFIFO}      

#爲併發線程建立一樣個數的佔位
for((i=1;i<=$THREAD;i++))
do
   echo ;  
 #借用read命令一次讀取一行的特性
 #使用一個echo默認輸出一個換行符,來確保每一行只有一個線程佔位
done >&5        #將佔位信息寫入管道 

#解壓數據 匹配對應類型type和時間戳
for i in `ls ${dir}/*${v_hour}*${type}*`
do 
  #從文件描述符管道中,獲取一個管道的線程佔位而後開始執行操做;
#read中 -u 後面跟fd,表示從文件描述符中讀入,該文件描述符能夠是exec新開啓的。
  read -u 5
  {
    tar -xzvf $i -C ${dir}/${temp}  #執行壓縮 
#任務執行完後在fd5中寫入一個佔位符,以保證這個線程執行完後,線程繼續保持佔位
#繼而維持管道中永遠是固定線程數,&表示該部分命令/任務放入後臺不佔當前的bash,實現並行處理
    echo "" >&5 
  }&
done 

#等待前面的線程執行
wait  

exec 5>&-  #關閉fd5的管道
複製代碼

此節參考文章:blog.csdn.net/qq_34409701…ui

相關文章
相關標籤/搜索