1 bash后臺(tái)運(yùn)行實(shí)現(xiàn)多進(jìn)程
1.1 command & 后臺(tái)運(yùn)行
釋放終端命令行,將command命令程序掛到后臺(tái)繼續(xù)執(zhí)行愉舔,這樣用戶就不必等待該程序執(zhí)行結(jié)束后才釋放終端命令行泄私,可以一邊等待command后臺(tái)執(zhí)行一邊做其他的事。但是肃廓,不可以關(guān)閉當(dāng)前的終端缀程,掛靠在后臺(tái)的command命令是依賴于當(dāng)前終端的,當(dāng)關(guān)閉當(dāng)前終端之后合瓢,后臺(tái)的comman命令也會(huì)終止執(zhí)行浑测。
比如:使用sort指令對(duì)一個(gè)較大的文件進(jìn)行排序
$ sort log > log.sorted &
1.2 nohup command & 后臺(tái)運(yùn)行
這種方式與之前的區(qū)別是,使用nohup來管理后臺(tái)執(zhí)行的command程序歪玲。這樣可以是后臺(tái)的command程序完全脫離終端,當(dāng)終端關(guān)閉時(shí)掷匠,后臺(tái)的command程序會(huì)在nohup管理下繼續(xù)執(zhí)行滥崩。如果你要運(yùn)行一個(gè)非常耗時(shí)的程序時(shí),建議使用nohup來管理后臺(tái)程序讹语。這是因?yàn)楦破ぃ?dāng)程序運(yùn)行過程中,終端因?yàn)榫W(wǎng)速不穩(wěn)定或者其他原因突然中斷時(shí)顽决,會(huì)導(dǎo)致運(yùn)行中的程序中斷短条。
使用方式:
$ nohup longtime.sh &
程序執(zhí)行過程中的正常輸出以及錯(cuò)誤輸出都被重定向到程序目錄下的nohup.out文件中。也可以使用如下方式來指定重定向輸出的文件:
$ nohup longtime.sh > myout 2>&1 &
1.3 后臺(tái)任務(wù)實(shí)現(xiàn)多進(jìn)程
只需將需要多進(jìn)程執(zhí)行的程序塊全部使用command & 轉(zhuǎn)移到后臺(tái)執(zhí)行即可才菠。
#!/bin/bash
start=`date +"%s"`
for (( i=0; i<10; i++ ))
do
{
echo "multiprocess"
sleep 3
} & #將上述程序塊放到后臺(tái)執(zhí)行
done
wait #等待上述程序結(jié)束
end=`date +"%s"`
echo "time: " `expr $end - $start`
使用上述方式茸时,10次執(zhí)行過程全部放到后臺(tái)執(zhí)行。這種方式雖然可以實(shí)現(xiàn)程序的多進(jìn)程并發(fā)執(zhí)行赋访,但是我們無法控制運(yùn)行在后臺(tái)的進(jìn)程數(shù)可都。為了實(shí)現(xiàn)進(jìn)程數(shù)控制,需要使用管道和文件描述符蚓耽。
2 使用fifo管道管理多進(jìn)程
2.1 管道
管道可用于程序之間的數(shù)據(jù)共享渠牲,但是需要注意的是,這種數(shù)據(jù)共享是單向的步悠。管道分兩種:匿名管道和有名管道签杈,這里僅討論有名管道。
管道的特點(diǎn):
1鼎兽、需要有兩個(gè)程序分別連接管道的兩端答姥,一個(gè)程序往管道里寫數(shù)據(jù)铣除,另一個(gè)程序從管道里取數(shù)據(jù);
2踢涌、只有寫數(shù)據(jù)的程序時(shí)通孽,寫入操作會(huì)一直處理阻塞狀態(tài),直到有另外的程序從管道中讀數(shù)據(jù)睁壁;同理當(dāng)只有讀取的程序時(shí)背苦,讀取操作也會(huì)一直處于阻塞狀態(tài),直到有另外的程序往管道里寫數(shù)據(jù)
3潘明、當(dāng)管道中沒有數(shù)據(jù)時(shí)行剂,取數(shù)據(jù)的程序會(huì)被阻塞,直到寫數(shù)據(jù)的程序?qū)憯?shù)據(jù)到管道
有名管道被稱為fifo有如下特點(diǎn):
1钳降、fifo擁有名稱厚宰,并存在于文件系統(tǒng)之中
2、除非fifo兩端同時(shí)存在讀和寫的程序遂填,否則fifo的數(shù)據(jù)流將會(huì)阻塞
3铲觉、fifo由mkfifo這樣的命令創(chuàng)建,而匿名管道是由shell自動(dòng)創(chuàng)建
4吓坚、fifo是一個(gè)雙向的字節(jié)流撵幽,數(shù)據(jù)流沒有任何格式
2.2 使用fifo管理shell多進(jìn)程
直接代碼:
1 #!/bin/bash
2
3 if [ $# -ne 1 ]
4 then
5 echo Usage: split.sh 201610
6 exit 1
7 else
8 month=$1
9 fi
10 len=`echo $month | wc -L`
11 if [ $len != "6" ]
12 then
13 echo "err> The lenght of month is not valid ..."
14 fi
15
16
17 fp_out="/opt/log_combine/"
18 fp_tmp="/opt/log_combine/tmp/"
19 fp_in="/opt/tag_log/tag.log."
20
21 #獲取所有日志文件的文件名
22 fns=`ls $fp_in$month*.gz`
23 if ls $fns >> log.split4month
24 then
25 echo "split the log begin!"
26 else
27 echo "err> can't find the file $fns"
28 exit 1
29 fi
30
31 trap "exec 1000>&-;exec 1000<&-;exit 0" 2
32
33 tmpfifo=$$.fifo
34 mkfifo $tmpfifo
35 exec 1000<>$tmpfifo
36 rm -fr $tmpfifo
37
38 thread_num=`grep "processor" /proc/cpuinfo | sort -u | wc -l`
39
40 for (( i=0; i<$thread_num; i++ ))
41 do
42 echo >&1000
43 done
44
45 for fn in $fns
46 do
47 fn_tmp=${fn##*/}
48 read -u1000
49 {
50 echo `date` $fn "begin!"
51 zcat $fn | gawk -F"\001" 'NF==6{
52 if($1~/\./){
53 suf = substr($1, index($1, ".")-1, 1)
54 }else{
55 suf = substr($1, length($1))
56 }
57
58 if(suf~/[0-9a-f]/){
59 print $1"\001"$2"\001"$4"\001"$6 >> "'$fp_tmp$fn_tmp'_" suf "_split"
60 #}else{
61 # print $0
62 }
63 }'
64 echo `date` $fn "end!"
65 echo >&1000
66 } &
67 done
68 echo "done !!!!!!"
- 31行:trap命令,程序接收Ctrl+c終端信號(hào)的處理
- exec 1000>&-:關(guān)閉文件描述符1000的寫
- exec 1000<&-:關(guān)閉文件描述符1000的讀
- 2:接收的是Ctrl+c信號(hào)
- 33-36行:
- 33行:獲取當(dāng)前程序的進(jìn)程號(hào)
- 34行:mkfifo創(chuàng)建管道礁击,管道名為當(dāng)前進(jìn)程的進(jìn)程號(hào)
- 35行:exec命令盐杂,將文件描述符1000與上述管道進(jìn)行綁定,其中<是讀綁定哆窿,>是寫綁定链烈,這里可以使用<>將讀寫同時(shí)與管道進(jìn)行綁定
- 36行:刪除管道文件(不太明白為啥在這里就刪除它)
- 特別說明:這里為何要將管道文件和文件描述符進(jìn)行綁定,直接使用管道文件不可以嗎挚躯?答案肯定是不可以强衡,以下內(nèi)容是我自己的理解。要實(shí)現(xiàn)多進(jìn)程控制码荔,就必須使用兩個(gè)功能:第一食侮,管道的特殊性質(zhì)(阻塞功能);第二目胡,通過對(duì)文件描述符的read和echo操作來控制管道中的數(shù)據(jù)內(nèi)容(這才是控制多進(jìn)程數(shù)量的關(guān)鍵)锯七。為了滿足上述功能,只能是將文件描述符和fifo綁定誉己,使文件描述符同時(shí)具有文件讀寫功能以及管道功能
- 38行:獲取當(dāng)前系統(tǒng)的線程數(shù)N眉尸,以此為并行運(yùn)行的進(jìn)程數(shù)
- 40-42行:向文件描述符1000中寫入N的空行,用來控制并行的進(jìn)程數(shù)
- 45-67行:并行開啟N的進(jìn)程處理日志文件
- 48行:要從文件描述符1000中讀取一行,如果當(dāng)前文件描述符1000沒有任何內(nèi)容噪猾,read命令就會(huì)被阻塞(由管道特點(diǎn)決定)
- 49-66行:需要并行處理的程序塊霉祸,其中66行最后的&表示將這個(gè)程序塊放到后臺(tái)執(zhí)行
- 特別說明:最初管道中有N的空行,會(huì)有N個(gè)read命令順利執(zhí)行袱蜡,后續(xù)的程序快也可以繼續(xù)往下執(zhí)行丝蹭,但是后續(xù)的一個(gè)read命令因?yàn)楣艿乐袥]有任何內(nèi)容全部被阻塞,當(dāng)執(zhí)行中的某個(gè)程序塊執(zhí)行到65行時(shí)坪蚁,會(huì)往管道中寫入一個(gè)空行奔穿,于是阻塞隊(duì)列中的read命令會(huì)從管道中讀取到一個(gè)空行,后續(xù)程序塊被放到后臺(tái)得到執(zhí)行敏晤。這就是通過fifo對(duì)并行程序進(jìn)行控制的關(guān)鍵贱田。