shell腳本多任務並發執行
轉自:https://blog.51cto.com/yttitan/2409618
正常情況下,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
因而當要循環執行的命令之間沒有依賴關系時,完全可以采用並發執行的方式,這樣可以大幅提高代碼執行效率。當然並發執行也有缺陷,就是當需要並行執行的命令數量特別多,特別是所執行的命令占用的系統資源非常多時,可能會將整個系統的資源全部耗盡,影響其它程序的運行,因而還可以借助其它技術來限制並發執行的進程數量,由於比較復雜,本文就不做介紹了。