bash指令碼併發執行

2021-10-09 19:39:13 字數 3318 閱讀 7238

目錄背景

採用gnu的paralle程式

並行化方法: {}&+wait 缺點

程序數可控的並行化方法: 命名管道

在linux下執行作業時, 經常會遇到以下情形: 有大量作業需要執行, 完成每個作業所需要的時間也不是很長. 如果我們以序列方式來執行這些作業, 可能要耗費較長的時間; 若採用並行方式執行則可以大大節約執行時間. 再者, 目前的計算機絕大部分都是多核架構, 要想充分發揮它們的計算能力也需要並行化. 

parallel是gnu專門用於並行化的乙個程式, 對於簡單的批量作業並行化非常合適. 使用parallel不需要編寫指令碼, 只需在原命令的基礎上簡單地加上parallel就可以了. 所以, 如果能用paralle並行化你的作業, 請優先使用. 有關paralle的詳細說明, 請參考其官方文件.

利用bash的**塊後台執行{}&wait函式, 可實現最簡單的批量作業並行化. 

如下面的**, 序列執行大約需要10秒

# cat aa.sh

for((i=1; i<=3; i++))

do     sleep 3

echo "done!"

done

# time sh aa.sh

done!

done!

done!

real 0m9.011s

user 0m0.002s

sys 0m0.009s

改為下面的簡單並行**理想情況下可將執行時間壓縮到3秒左右:

# cat aa2.sh 

for((i=1; i<=3; i++))

do & done

wait

# time sh aa2.sh

done!

done!

done!

real 0m3.008s

user 0m0.007s

sys 0m0.008s

使用bash指令碼同時執行多個程序並無困難, 主要存在的問題是如何控制同時執行的程序數目. 上面的簡單並行化方法使用時程序數無法控制, 因而功能有限, 因為大多數時候我們需要執行的作業數遠遠超過可用處理器數, 這種情況下若大量作業同時在後台執行, 會導致執行速度變慢, 並行效率大大下降. 

命名管道是linux下程序間進行通訊的一種方法, 也稱為先入先出(fifo, first in first out)檔案. 具體方法是建立乙個fifo檔案, 作為程序池, 裡面存放一定數目的」令牌」. 作業執行規則如下: 所有作業排隊依次領取令牌; 每個作業執行前從程序池中領取一塊令牌, 完成後再歸還令牌; 當程序池中沒有令牌時, 要執行的作業只能等待. 這樣就能保證同時執行的作業數等於令牌數. 

njob=10    # 作業數目

nproc=5 # 可同時執行的最大作業數

function cmd

pfifo="/tmp/$$.fifo" # 以pid為名, 防止建立命名管道時與已有檔案重名,從而失敗

mkfifo $pfifo # 建立命名管道

exec 6<>$pfifo # 以讀寫方式開啟命名管道, 檔案識別符號fd為6

# fd可取除0, 1, 2,5外0-9中的任意數字

rm -f $pfifo # 刪除檔案, 也可不刪除, 不影響後面操作

# 在fd6中放置$nproc個空行作為令牌

for((i=1; i<=$nproc; i++)); do

echo

done >&6

for((i=1; i<=$njob; i++)); do # 依次提交作業

read -u6 # 領取令牌, 即從fd6中讀取行, 每次一行

# 對管道,讀一行便少一行,每次只能讀取一行

# 所有行讀取完畢, 執行掛起, 直到管道再次有可讀行

# 因此實現了程序數量控制

|| sleep 1 # 暫停1秒,可根據需要適當延長,

# 關鍵點,給系統緩衝時間,達到限制並行程序數量的作用

echo >&6 # 歸還令牌, 即程序結束後,再寫入一行,使掛起的迴圈繼續執行

} &done

wait # 等待所有的後台子程序結束

exec 6>&- # 刪除檔案識別符號

說明:

(1) exec 6<>$pfifo 這一句很重要, 若無此語句, 向$pfifo寫入資料時, 程式會被阻塞, 直到有read讀出了檔案中的資料為止. 而執行了此語句, 就可以在程式執行期間不斷向檔案寫入資料而不會阻塞, 並且資料會被儲存下來以供read讀出.

(2) 當$pfifo中已經沒有資料時, read無法讀到資料, 程序會被阻塞在read操作上, 直到有子程序執行結束, 向$pfifo寫入一行.

(3) 核心執行部分也可使用如下方式

for((i=1; i<=$njob; i++)); do

read -u6

(cmd $i; sleep 1; echo >&6) &

done

# cat cc.sh

echo "pid: $$ start"

&"echo "{}& pid: $$"

sleep 100}&(

echo "()&"

echo "()& pid $$"

sleep 100

)&echo "pid: $$ end"

wait

# 執行結果如下所示:

# sh cc.sh # 視窗一

# ps -ef |grep cc # 視窗二

root 46849 44246 0 10:17 pts/1 00:00:00 sh cc.sh

root 46850 46849 0 10:17 pts/1 00:00:00 sh cc.sh

root 46851 46849 0 10:17 pts/1 00:00:00 sh cc.sh

root 47245 46232 0 10:17 pts/0 00:00:00 grep --color=auto cc

# pstree -p 44246

bash(44246)───sh(46849)─┬─sh(46850)───sleep(46852)

└─sh(46851)───sleep(46853)

#總結:

()&, {}& 都會產生子 shell;

Python併發執行

使用map簡化併發的複雜度,生產者消費者模型實在看的頭疼 參考這篇帖子說明的很清楚 from multiprocessing.dummy import pool as threadpool import requests import time urls 定義網頁資源集合 for i in rang...

Go 併發執行

需要併發執行的場景有很多 爬蟲 拉取資料 更新資料 go作為天生高併發的語言,在使用併發時是比較方便的。package main import fmt func main description 開啟多執行緒執行 param total 啟動執行緒數 param work 需要執行的方法 func ...

什麼是併發執行?

1 併發執行就是讓計算機同時執行幾個程式或同時執行同一程式多個程序或執行緒。2 早期的計算機只具有乙個 處理器 cpu 並且是單核 只有乙個運算器 的,這種情況下計算機作業系統採用併發技術實現併發執行,具體做法是採用 時間片輪詢程序排程演算法 它的思想簡單介紹如下 在作業系統的管理下,所有正在執行的...