轉載:http://blog.chinaunix.net/uid-27571599-id-3473078.html
很多人都問我如何寫shell指令碼,如何?同時給三台ftp伺服器上傳檔案,如何同時檢測三台伺服器是否alive等,其實這就是想實現shell的並發。那麼shell並發該如何?呢。 下面我就拿這個例子來講:
每次任務都是輸出字元“bingfa”,並停留一秒鐘,共20次。
按照正常思維,指令碼應該這樣寫:
[root@station1 ~]# cat a.sh #!/bin/bash for((i=0;i<20;i++)) do sleep 1 echo "bingfa" done [root@station1 ~]# time bash a.sh bingfa bingfa bingfa bingfa bingfa bingfa bingfa bingfa bingfa bingfa bingfa bingfa bingfa bingfa bingfa bingfa bingfa bingfa bingfa bingfa real 0m20.067s user 0m0.016s sys 0m0.031s [root@station1 ~]# 可以看到執行此指令碼大概用了20秒。那麼使用shell並發該怎麼寫,很多人都會想到背景程式,類似如下:
[root@station1 ~]# cat b.sh #!/bin/bash for((i=0;i<20;i++)) do { sleep 1 echo "bingfa" }& done wait [root@station1 ~]# time bash b.sh bingfa bingfa bingfa bingfa bingfa bingfa bingfa bingfa bingfa bingfa bingfa bingfa bingfa bingfa bingfa bingfa bingfa bingfa bingfa bingfa real 0m1.060s user 0m0.005s sys 0m0.057s [root@station1 ~]#
這樣寫只需花大概一秒鐘,可以看到所有的任務幾乎同時執行,如果任務量非常大,系統肯定承受不了,也會影響系統中其他程式的運行,這樣就需要一個線程數量的控制。下面是我一開始寫的代碼(是有問題的):
[root@station1 ~]# cat c.sh #!/bin/bash exec 6<>tmpfile echo "1\n1\n1" &>6 for((i=0;i<20;i++)) do read -u 6 { sleep 1 echo "$REPLY" echo "1" 1>&6 }& done wait [root@station1 ~]# time bash c.sh 111 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 real 0m1.074s user 0m0.012s sys 0m0.031s [root@station1 ~]#
可以明顯看出是有問題的,我本想控制線程個數為3,但是就算檔案描述符6中為空白,也會被讀取空,然後跳過繼續下面的執行,所以使用檔案描述符開啟一個檔案是不行的,然後我就想著使用類似管道的檔案來做,下面是My Code:
[root@station1 ~]# cat d.sh #!/bin/bash mkfifo fd2 exec 9<>fd2 echo -n -e "1\n1\n1\n" 1>&9 for((i=0;i<20;i++)) do read -u 9 { #your process sleep 1 echo "$REPLY" echo -ne "1\n" 1>&9 } & done wait rm -f fd2 [root@station1 ~]# time bash d.sh 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 real 0m7.075s user 0m0.018s sys 0m0.044s [root@station1 ~]# 這樣就ok了,三個線程運行20個任務,7秒多點。