Shell腳本中的多任務併發執行

正常情況下,Shell腳本中的命令是串行執行的,當一條命令執行完纔會執行接下來的命令。比如下面這段代碼:

 #!/bin/bash
for i in {1..10};do
echo $i 
done
echo "END"

執行結果:

1
2
3
4
5
6
7
8
9
10
END

可以看到,循環體中的“echo $i”命令是串行執行的。但是如果所執行的命令耗時比較長,這就會導致整個程序的執行時間非常長,甚至可能導致程序執行時卡在那裏,長時間失去響應。
比如我們需要完成這樣一個任務:編寫一個腳本,掃描192.168.80.0/24網絡裏,當前在線的主機有哪些,能ping通就認爲在線。
要完成這個任務,編寫腳本並不複雜,下面是寫好的代碼:

 #!/bin/bash
for i in {1..254};do
        ip="192.168.80.$i"
        ping -c 2 $ip &> /dev/null && echo $ip is up 
done

這裏對腳本中使用的ping命令稍作說明。Linux中的ping命令在執行後會連續不斷地發包,因而腳本中的ping命令使用了“-c”選項,指定只發2次包,如果能收到響應,就認爲目標主機在線。
這個腳本在邏輯上並沒有問題,但是在執行後由於要對網絡中的254個IP地址輪流執行ping命令,耗時非常長,而且此時的腳本無法使用Ctrl+C強制終止,只能使用Ctrl+Z轉入後臺,然後再用kill命令強制結束進程。

 [root@localhost ~]# bash ping.sh
192.168.80.1 is up
192.168.80.2 is up
^C
^Z
[1]+  已停止               bash ping.sh
[root@localhost ~]# jobs -l                             #查看後臺工作任務
[1]+ 101100 停止                  bash ping.sh
[root@localhost ~]# kill -9 101100                      #強制結束進程
[root@localhost ~]# 
[1]+  已殺死               bash ping.sh

實際上在這個腳本中所循環執行的ping命令之間並沒有依賴關係,也就是說不必非要等到“ping 192.168.80.1”結束之後才能接着執行“ping 192.168.80.2”,所有的這些ping命令完全可以併發執行。
如果是使用Python,那麼可以藉助於多線程技術來實現命令的併發執行,而Shell不支持多線程,因而只能採用多進程的方式。具體的實現方法很簡單,就是在要併發執行的命令後面加上“&”,將其轉入後臺執行,這樣就可以在執行完一條命令之後,不必等待其執行結束,就立即轉去執行下一條命令。
我們還是以之前的代碼爲例,在循環體中的echo命令之後加上“&”:

 #!/bin/bash
for i in {1..10};do
echo $i &
done
echo "END"

執行結果:

 [root@localhost ~]# bash test.sh
END
[root@localhost ~]# 1
2
3
6
7
4
8
9
10
5

可以看到,在併發執行時不能保證命令的執行順序,而且本應在整個循環執行結束之後再執行的echo "END"命令,卻在程序一開始就被執行了。所以在併發執行時,我們通常都需要保證在循環體中的所有命令都執行完後再向後執行接下來的命令,這時就可以使用 wait命令來實現。在Shell中使用wait命令,相當於其它高級語言裏的多線程同步。
下面對代碼進行改進,增加wait命令:

 #!/bin/bash
for i in {1..10};do
echo $i &
done
wait
echo "END"

這樣執行結果就正常了:

 [root@localhost ~]# bash test3.sh
6
7
2
3
4
8
9
10
5
1
END

瞭解了程序併發執行的原理之後,我們對ping腳本也同樣進行改進:

 #!/bin/bash
for i in {1..254};do
        ip="192.168.80.$i"
        ping -c 2 $ip &> /dev/null && echo $ip is up &
done
wait

此時腳本的執行速度將大大提高:

 [root@localhost ~]# bash ping.sh
192.168.80.10 is up
192.168.80.20 is up
192.168.80.2 is up
192.168.80.1 is up
192.168.80.135 is up

因而當要循環執行的命令之間沒有依賴關係時,完全可以採用併發執行的方式,這樣可以大幅提高代碼執行效率。當然併發執行也有缺陷,就是當需要並行執行的命令數量特別多,特別是所執行的命令佔用的系統資源非常多時,可能會將整個系統的資源全部耗盡,影響其它程序的運行,因而還可以藉助其它技術來限制併發執行的進程數量,由於比較複雜,本文就不做介紹了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章