Linux Shell腳本如何實(shí)現(xiàn)多線程

2020年10月13日16:56:32 發(fā)表評(píng)論 4,642 ℃

當(dāng)我們工作中遇到一些批量分發(fā)、批量執(zhí)行場(chǎng)景時(shí),寫的一些shell腳本都是單線程任務(wù),當(dāng)然這些量級(jí)不大的時(shí)候,看不出劣勢(shì)。

舉個(gè)例子:現(xiàn)在需要通過(guò)跳板機(jī),分發(fā)一個(gè)文件到10臺(tái)服務(wù)器,每臺(tái)服務(wù)器傳輸需要1s時(shí)間,10臺(tái)服務(wù)器傳輸完就是10s。看下面腳本,這里通過(guò)sleep命令模擬傳輸耗時(shí)。

#!/bin/bash
#Author: www.zhongjima.net
#Description: 模擬分發(fā)文件到10臺(tái)服務(wù)器
startTime=`date +%s`
for i in `seq 10`;do
    echo $i
    sleep 1
done
stopTime=`date +%s`
echo "耗時(shí): $[$stopTime - $startTime] s"

這個(gè)執(zhí)行結(jié)果不用思考,就是10s。

# bash test.sh 
1
2
3
4
5
6
7
8
9
10
耗時(shí): 10 s

如果是500臺(tái)服務(wù)器或者1000臺(tái)服務(wù)器,那命令執(zhí)行以后就慢慢等吧。那如果文件比較大,一個(gè)需要30s呢?1000 * 30 =30000 s 基本上就是8個(gè)多小時(shí)。早上上班執(zhí)行,等到下班剛剛好,如果你的腳本是前臺(tái)運(yùn)行,中間突然網(wǎng)絡(luò)波動(dòng),導(dǎo)致遠(yuǎn)程斷開了,那就廁所哭去吧。

其實(shí)文件分發(fā)大不了就是等嘛,但是如果是批量檢查服務(wù)器狀態(tài),或者批量啟動(dòng)服務(wù),服務(wù)器數(shù)量一大,那劣勢(shì)就特別明顯了。

那么有沒(méi)有辦法提高效率呢?答案是肯定的,利用多線程,本來(lái)需要10s完成的任務(wù),我使用了5個(gè)線程,那么跑下來(lái)基本也就2s左右。shell不像 python、go語(yǔ)言,他們本身就有多線程模塊。

shell只能利用管道和文件描述符實(shí)現(xiàn)多線程任務(wù),直接腳本測(cè)試剛才的分發(fā)文件。

#!/bin/bash
#Author: www.zhongjima.net
#Description: 模擬多線程分發(fā)文件到10臺(tái)服務(wù)器
startTime=`date +%s`
tmpfifo="/tmp/$$.fifo"
[ -e $tmpfifo ] || mkfifo $tmpfifo
exec 3<>$tmpfifo
rm -rf $tmpfifo
for i in `seq 5`;do
    echo >&3
done
for i in `seq 10`;do
    read -u3
    {
        sleep 1
        echo $i
        echo >&3
    }&
done
wait
stopTime=`date +%s`
echo "耗時(shí): $[$stopTime - $startTime] s"
exec 3<&-
exec 3>&-

執(zhí)行結(jié)果如下圖:

Linux Shell腳本如何實(shí)現(xiàn)多線程

如果是10個(gè)線程,結(jié)果就是1s,如果是6、7、8、9個(gè)線程,整個(gè)任務(wù)執(zhí)行完也是2s,所以需要根據(jù)實(shí)際的情況設(shè)置線程數(shù),也并不是線程越多越好,整個(gè)要看本身執(zhí)行腳本的服務(wù)器CPU核數(shù)以及其它資源情況。

下面對(duì)腳本語(yǔ)句進(jìn)行分析:

#!/bin/bash
#Author: www.zhongjima.net
#Description: 模擬多線程分發(fā)文件到10臺(tái)服務(wù)器
startTime=`date +%s`
tmpfifo="/tmp/$$.fifo"

#判斷有名管道是否存在 創(chuàng)建有名管道文件
[ -e $tmpfifo ] || mkfifo $tmpfifo 

#創(chuàng)建文件描述符 exec 3<>$tmpfifo,(可讀(<)可寫(>))創(chuàng)建文件描述符3關(guān)聯(lián)管道文件,這時(shí)候3這個(gè)文件描述符就擁有了管道的所有特性。
#還具有一個(gè)管道不具有的特性:無(wú)限存不阻塞,無(wú)限取不阻塞,而不用關(guān)心管道內(nèi)是否為空,也不用關(guān)心是否有內(nèi)容寫入引用文件描述符: &3可以執(zhí)行n次echo >&3 往管道里放入n把鑰匙。并發(fā)n
exec 3<>$tmpfifo

#關(guān)聯(lián)后的文件描述符擁有管道文件的所有特性,所以這時(shí)候管道文件可以刪除,留下文件描述符來(lái)用就可以了。
rm -rf $tmpfifo

for i in `seq 5`;do
    #&3代表引用文件描述符3,這條命令代表往管道里面放入了一個(gè)"令牌",`seq 5` 循環(huán)5次,也就是5個(gè)令牌,即5個(gè)線程
    echo >&3
done

for i in `seq 10`;do
    #代表從管道中讀取一個(gè)令牌
    read -u3
    {
        sleep 1
        echo $i
        #代表我這一次命令執(zhí)行到最后,把令牌放回管道
        echo >&3
    }&   #用{}把循環(huán)體括起來(lái),后加一個(gè)&符號(hào),代表每次循環(huán)都把命令放入后臺(tái)運(yùn)行
done

#wait命令的意思是,等待(wait命令)上面的命令(放入后臺(tái)的)都執(zhí)行完畢了再往下執(zhí)行
wait

stopTime=`date +%s`
echo "耗時(shí): $[$stopTime - $startTime] s"

#關(guān)閉文件描述符的讀
exec 3<&-
#關(guān)閉文件描述符的寫
exec 3>&-

其實(shí)主要就是mkfifo和exec兩個(gè)命令的使用。

exec命令 

用于調(diào)用并執(zhí)行指令的命令。exec命令通常用在shell腳本程序中,可以調(diào)用其他的命令。如果在當(dāng)前終端中使用命令,則當(dāng)指定的命令執(zhí)行完畢后會(huì)立即退出終端。

Linux每打開一個(gè)shell就會(huì)打開默認(rèn)的三個(gè)文件描述符描0,1,2,分別代表標(biāo)準(zhǔn)輸入,標(biāo)準(zhǔn)輸出和標(biāo)準(zhǔn)錯(cuò)誤輸出。需要的時(shí)候我們可以使用exec命令指定一個(gè)大于3的數(shù)字作為文件。

1、exec 3</tmp/1.txt     #以“只讀方式”打開/tmp/1.txt,文件描述符對(duì)應(yīng)為3

2、exec 3>/tmp/1.txt     #以“只寫方式”打開/tmp/1.txt,文件描述符對(duì)應(yīng)為3

3、exec 3<>/tmp/1.txt    #以“讀寫方式”打開/tmp/1.txt,文件描述符對(duì)應(yīng)為3

4、exec 3<&-             #關(guān)閉文件描述符3

轉(zhuǎn)載請(qǐng)注明:阿湯博客->Linux Shell腳本如何實(shí)現(xiàn)多線程 http://www.zhongjima.net/atang_4575.html

【騰訊云】云服務(wù)器、云數(shù)據(jù)庫(kù)、COS、CDN、短信等云產(chǎn)品特惠熱賣中

發(fā)表評(píng)論

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: