shell多線程(2)之基於管道實現並發


在shell腳本里批量執行程序是比較常見的方式,如果程序很多,每個執行時間比較長,則順序執行需要花費大量的時間。

此時並發就成為我們考慮的方向。

上篇《shell多線程》中我們已經簡單實現了基於for循環的並發,可以顯著提高工作效率;

缺點是CPU的核心不是無限的,如果全部占用,則會影響系統的正常運行。

這個時候我們就考慮利用linux系統的管道來進行最大並發數的管控。

1.舉例:

一個廁所有10個蹲位,如果100個人來使用,則勢必形成競爭,這時管理員給每個蹲位一個鎖和一把鑰匙,先來的人拿鑰匙開鎖開始使用;

蹲位全部占滿后后面的人等待,當有一個蹲位空出,則交出鑰匙給等待隊列中的第一個人,如此循環,直到等待隊列為空。

2.文件描述符

管道具有存一個讀一個,讀完一個就少一個,沒有則阻塞,放回的可以重復取,這正是隊列特性,解決這個問題的關鍵就是文件描述符了。

3. mkfifo /tmp/fd1     

創建有名管道文件exec 3<>/tmp/fd1,創建文件描述符3關聯管道文件,這時候3這個文件描述符就擁有了管道的所有特性,還具有一個管道不具有的特性:無限存不阻塞,無限取不阻塞,而不用關心管道內是否為空,也不用關心是否有內容寫入引用文件描述符: &3可以執行n次echo >&3 往管道里放入n把鑰匙

4.完整代碼

#!/bin/bash

[ -e /tmp/fd1 ] || mkfifo /tmp/fd1 #創建有名管道
exec 3<>/tmp/fd1                   #創建文件描述符,以可讀(<)可寫(>)的方式關聯管道文件,這時候文件描述符3就有了有名管道文件的所有特性
rm -rf /tmp/fd1                    #關聯后的文件描述符擁有管道文件的所有特性,所以這時管道文件可以刪除,我們留下文件描述符來用就可以
for ((i=1;i<=10;i++))
do
        echo >&3                   #&3代表引用文件描述符3,這條命令代表往管道里面放入了一個"令牌",文件描述符可以使用0/1/2/225之外的其他數字,這幾個已被占用
done
 
for ((i=1;i<=100;i++))
do
read -u3                           #代表從管道中讀取一個令牌
{
        sleep 1  #sleep 1用來模仿執行一條命令需要花費的時間(可以用真實命令來代替)
        echo 'success'$i       
        echo >&3                   #代表我這一次命令執行到最后,把令牌放回管道
}&
done
wait
 
exec 3<&-                       #關閉文件描述符的讀
exec 3>&-                       #關閉文件描述符的寫

4.由於從前寫的腳本大部分都是以方法的形式存在的,所以想要落地就需要對上面的腳本做一些修改,保證每次循環都會執行一個方法

t1Fun(){
echo 1
}
t2Fun(){
echo 2
}
t3Fun(){
echo 3
}
t4Fun(){
echo 4
}
[ -e /tmp/fd1 ] || mkfifo /tmp/fd1
exec 3<>/tmp/fd1
rm -rf /tmp/fd1
for ((i=1;i<5;i++))
do
    echo >&3
done

for ((i=1;i<=4;i++))
do 
read -u3
{
    sleep 1
    if [ $i -eq 1 ];then
        t1Fun
    elif [ $i -eq 2 ];then
        t2Fun
    elif [ $i -eq 3 ];then
        t3Fun
    else
        t4Fun
    fi
    echo >&3
}&
done 
wait

exec 3<&-
exec 3>&-

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM