《Linux Shell多線程實現》要點:
本文介紹了Linux Shell多線程實現,希望對您有用。如果有疑問,可以聯系我們。
shell腳本的執行效率雖高,但當任務量巨大時仍然需要較長的時間,尤其是需要執行一大批的命令時.因為默認情況下,shell腳本中的命令是串行執行的.如果這些命令相互之間是獨立的,則可以使用“并發”的方式執行這些命令,這樣可以更好地利用系統資源,提升運行效率,縮短腳本執行的時間.如果命令相互之間存在交互,則情況就復雜了,那么不建議使用shell腳原來完成多線程的實現.
為了便利闡述,使用一段測試代碼.在這段代碼中,通過seq
命令輸出1到10,使用for...in
語句產生一個執行10次的循環.每一次循環都執行sleep 1
,并echo
出當前循環對應的數字.
注意:
請根據真實場景的各種情況理解本文想要表達的內容.
$ cat test1.sh
#/bin/bash
all_num=10
a=$(date +%H%M%S)
for num in `seq 1 ${all_num}`
do
sleep 1
echo ${num}
done
b=$(date +%H%M%S)
echo -e "startTime:\t$a"
echo -e "endTime:\t$b"
通過上述代碼可知,為了體現執行的光陰,將循環體開始前后的光陰打印了出來.
運行成果:
$ sh test1.sh
10次循環,每次sleep 1秒,所以總執行光陰10s.
在linux中,在命令的末尾加上&
符號,則表現該命令將在后臺執行,這樣后面的命令不用等待前面的命令執行完就可以開始執行了.示例中的循環體內有多條命令,則可以以{}
括起來,在大括號后面添加&
符號.
$ cat test2.sh
#/bin/bash
all_num=10
a=$(date +%H%M%S)
for num in `seq 1 ${all_num}`
do
{
sleep 1
echo ${num}
} &
done
b=$(date +%H%M%S)
echo -e "startTime:\t$a"
echo -e "endTime:\t$b"
運行成果:
sh test2.sh
startTime: 194147
endTime: 194147
[j-tester@merger142 ~/bin/multiple_process]$ 1
2
3
4
5
6
7
8
9
10
通過結果可知,程序沒有先打印數字,而是直接輸出了開始和結束時間,然后顯示出了命令提示符[j-tester@merger142 ~/bin/multiple_process]$
(出現命令提示符表現腳本已運行完畢),然后才是數字的輸出.這是因為循環體內的命令全部進入后臺,所以均在sleep了1秒以后輸出了數字.開始和結束時間相同,即循環體的執行時間不到1秒鐘,這是由于循環體在后臺執行,沒有占用腳本主進程的時間.
wait
命令辦理上面的問題,只需要在上述循環體的done語句后面加上wait
命令,該命令等待當前腳本進程下的子進程結束,再運行后面的語句.
$ cat test3.sh
#/bin/bash
all_num=10
a=$(date +%H%M%S)
for num in `seq 1 ${all_num}`
do
{
sleep 1
echo ${num}
} &
done
wait
b=$(date +%H%M%S)
echo -e "startTime:\t$a"
echo -e "endTime:\t$b"
運行成果:
$ sh test3.sh
1
2
3
4
5
6
7
9
8
10
startTime: 194221
endTime: 194222
但這樣依然存在一個問題:
因為&
使得所有循環體內的命令全部進入后臺運行,那么倘若循環的次數很多,會使操作系統在瞬間創建出所有的子進程,這會非常消耗系統的資源.如果循環體內的命令又很消耗系統資源,則成果可想而知.
最好的辦法是并發的進程是可配置的.
$ cat test4.sh
#/bin/bash
all_num=10
# 設置并發的進程數
thread_num=5
a=$(date +%H%M%S)
# mkfifo
tempfifo="my_temp_fifo"
mkfifo ${tempfifo}
# 使文件描述符為非阻塞式
exec 6<>${tempfifo}
rm -f ${tempfifo}
# 為文件描述符創建占位信息
for ((i=1;i<=${thread_num};i++))
do
{
echo
}
done >&6
#
for num in `seq 1 ${all_num}`
do
{
read -u6
{
sleep 1
echo ${num}
echo "" >&6
} &
}
done
wait
# 關閉fd6管道
exec 6>&-
b=$(date +%H%M%S)
echo -e "startTime:\t$a"
echo -e "endTime:\t$b"
運行成果:
$ sh test4.sh
1
3
2
4
5
6
7
8
9
10
startTime: 195227
endTime: 195229
xargs -P
控制并發數xargs命令有一個-P
參數,表現支持的最大進程數,默認為1.為0時表現盡可能地大,即方案2
的效果.
$ cat test5.sh
#/bin/bash
all_num=10
thread_num=5
a=$(date +%H%M%S)
seq 1 ${all_num} | xargs -n 1 -I {} -P ${thread_num} sh -c "sleep 1;echo {}"
b=$(date +%H%M%S)
echo -e "startTime:\t$a"
echo -e "endTime:\t$b"
運行成果:
$ sh test5.sh
1
2
3
4
5
6
8
7
9
10
startTime: 195257
endTime: 195259
GNU parallel
命令控制并發數GNU parallel
命令是非常強年夜的并行計算命令,使用-j
參數控制其并發數量.
$ cat test6.sh
#/bin/bash
all_num=10
thread_num=6
a=$(date +%H%M%S)
parallel -j 5 "sleep 1;echo {}" ::: `seq 1 10`
b=$(date +%H%M%S)
echo -e "startTime:\t$a"
echo -e "endTime:\t$b"
運行成果:
$ sh test6.sh
1
2
3
4
5
6
7
8
9
10
startTime: 195616
endTime: 195618
“多線程”的好處不言而喻,雖然shell中并沒有真正的多線程,但上述辦理方案可以實現“多線程”的效果,重要的是,在實際編寫腳本時應有這樣的考慮和實現.
另外:
方案3、4、5雖然都可以控制并發數量,但方案3顯然寫起來太繁瑣.
方案4和5都以非常簡潔的形式完成了控制并發數的效果,但由于方案5的parallel命令非常強大,所以十分建議系統學習下.
方案3、4、5設置的并發數均為5,實際編寫時可以將該值作為一個參數傳入.
&
后臺運行本文永久更新鏈接地址:http://www.linuxidc.com/Linux/2017-06/145162.htm
歡迎參與《Linux Shell多線程實現》討論,分享您的想法,維易PHP學院為您提供專業教程。