天天看點

[shell]-(一)關于多線程的管道與描述符的運用[shell]-(一)關于多線程的管道與描述符的運用

[shell]-(一)關于多線程的管道與描述符的運用

shell雖然執行效率差,但優點,是所用即所得,不用移植,基本上所有linux都通用,基本不用額外安裝程式。s

當然運用的好的話,效率也不會太差。比如,盡可能的減少讀寫檔案,減少無名管道“|”的使用,大量的循環盡可能用awk裡完成,還有多線程的使用。

多線程,就是讓shell同時執行多行指令。

shell裡并不能同時接收多條指令,也就是,必須逐行逐條執行,想要實作執行多行,可以把前一條指令置入背景,後面的指令就可以不必等待前一條的完畢,而是立即執行。

# 背景執行在指令行結尾加”空格&“

# while true;do sleep 5s;done &

# while true;do sleep 5s;done

^C

# while true;do sleep 5s;done &

#

           

這樣就可以很開心的多行執行指令了:# cat proc.sh

#!/bin/bash

for i in $(seq 5);do

        echo "While A 01 : $i" >>proc_test.txt

        echo "While A 02 : $i" >>proc_test.txt

        echo "While A 03 : $i" >>proc_test.txt

        sleep 1s

done &

for j in $(seq 5);do

        echo " While B 01 : $j" >>proc_test.txt

        echo " While B 02 : $j" >>proc_test.txt

        echo " While B 03 : $j" >>proc_test.txt

        sleep 0.5s

done &

wait
           

預想的是向檔案proc_test.txt每次輸入三行,而實際。。。。。

cat proc_test.txt

# sh proc.sh

# cat proc_test.txt

While A 01 : 1

While A 02 : 1

While B 02 :

While A 03 : 1

While B 03 :

While B 02 :

While B 03 :

While A 01 : 2

While A 02 : 2

While A 03 : 2

While B 02 :

While B 03 :

While B 02 :

While B 03 :

While A 01 : 3

While A 02 : 3

While A 03 : 3

While B 02 :

While B 03 :

While A 01 : 4

While A 02 : 4

While A 03 : 4

While A 01 : 5

While A 02 : 5

While A 03 : 5

#
           

不但行是亂的,列也出現了混亂。。出現這種情況,是因為在while A輸出時,while B也在輸出,當對同一個檔案寫入時,A B的内容就被混編寫入了檔案。

這種混亂的多線程,并不是我們想要的。

必須得讓他們有順序的輸出。

管道!這時就該他發揮作用了。

管道就像名字一樣,是一個運載資料流的通道,可以像水管一樣控制它的開關和流速。

mkfifo用于建立管道檔案。

# mkfifo t.fifo

# ls -l t.fifo

prw-r--r-- 1 root root 0 Nov 13 15:44 t.fifo

#
           

建立個名為 t.fifo的管道檔案

管道可以像普通檔案一樣的讀寫操作,但是有容量限制,一般是1024位元組

向管道寫入時,必須同時讀取,否則,寫入端處于停滞狀态。反之也是,

從管道讀取時,如果管道内沒有資料,讀取端也會處于停滞狀态。

這裡就是關鍵。看到”停滞“了嗎,如果當while A寫入檔案時,讓其它while寫入這個檔案的指令行處于停滞,那麼A寫入的内容就不會被B打亂了。

這樣基本的概念就實作了。

[shell]-(一)關于多線程的管道與描述符的運用[shell]-(一)關于多線程的管道與描述符的運用

因為管道檔案讀寫必須同步,是以這裡用到描述符

exec 描述符<>管道

<表示讀操作,>表示寫操作

echo >&100 ,向100裡輸入一行,代表一個執行令牌

read <&100 ,從100裡讀取一個令牌,也可用read -u100,如果沒有則停滞,等待新的令牌輸入

echo >&100 ,while裡這條,三行一組輸出完成時,回交令牌。

{}把多行指令分成一組

注:描述符隻在目前shell裡,或者說,目前程序及其子程序有效,

        而管道檔案,是整個系統有效。是以在定義完描述符,可以 # rm t.fifo

        如果讀寫不同步時

[shell]-(一)關于多線程的管道與描述符的運用[shell]-(一)關于多線程的管道與描述符的運用

每三行一組的輸出基本實作了

#cat proc_test.txt

[shell]-(一)關于多線程的管道與描述符的運用[shell]-(一)關于多線程的管道與描述符的運用

最後的小問題,當echo $i >>file.txt時,是處于背景,是以{}外的$i 不會影響{}裡的$i 的值。

上面已基本完成一個多線程的規範輸出,但如果whileAB都是無限循環,且背景部分要更耗時,那麼shell下的while程序就會不斷的增加,增加到無限多。最終系統承載不住,就會當機。

這并不是我們希望發生的,那麼就應該限制一下,背景的最大數量。

解決方法很多,當然你也可以用記數循環+循環的套用來實作、

在這裡,我們要用管道的讀寫特性來實作背景數量的限制。

和前面的有序輸出是同一個原理,有序輸出,每次隻能讀取一個執行令牌,也就是單車道。

那麼我們為背景程序新開設個多車道,就暫定為5道并開。

#!/bin/bash

mkfifo t.fifo # 建立管道檔案

exec 100<>t.fifo #定義描述符

# 1車道

echo >&100

mkfifo  proc.fifo proc2.fifo #定義2兩管道檔案

exec 101<>proc.fifo  #定義描述符

exec 102<>proc.fifo  #定義描述符

# 開通5車道

echo |tee >&101 >&102

echo |tee >&101 >&102

echo |tee >&101 >&102

echo |tee >&101 >&102

echo |tee >&101 >&102

# 這裡定義個管道,用于,外部向腳本發送指令

mkfifo manager.fifo

exec 1000<manager.fifo

for i in $(seq 5);do

    read <&101 #如果沒有補充,最多讀取5次,否則停滞等待

    {

    read <&100

        echo "While A 01 : $i" >>proc_test.txt

        echo "While A 02 : $i" >>proc_test.txt

        echo "While A 03 : $i" >>proc_test.txt

        echo >&100 # 補充1次

    } &

    echo >&101

    sleep 1s

done &

for j in $(seq 5);do

    read <&101  #如果沒有補充,最多讀取5次,否則停滞等待

    {

    read <&100

        echo " While B 01 : $j" >>proc_test.txt

        echo " While B 02 : $j" >>proc_test.txt

        echo " While B 03 : $j" >>proc_test.txt

    echo >&101  # 補充1次

    } &

    sleep 0.5s

done &

while true;do

    read -u1000 manager

    # 試試在腳本執行時,再開啟個終端,并echo "hello shell" > manager.fifo

    # 腳本會接收到這個資訊,并列印出來。

    echo -e "\t\t這裡是從腳本外得到的輸入内容 : $manager"

done

wait
           
[shell]-(一)關于多線程的管道與描述符的運用[shell]-(一)關于多線程的管道與描述符的運用

如此這般,雙背景的5線程并行就設定好了

注:echo |tee >&101 >&102 相當于

echo >&101 ;echo >&102

tee 把輸出的内容分流給2個指向tee -a file是追加模式

最後附加了,從腳本外向腳本内傳送資訊。

第一次寫東西,有點亂。

下一篇 ---->  定義管道的通用腳本