本隨筆主要講述在shell編程中實現任務並發處理。
參考自:https://www.cnblogs.com/pmars/archive/2012/11/15/2771609.html
一、調度腳本
#!/bin/sh
help()
{
echo "使用說明:"
echo " $0 子進程腳本 [slots]"
exit
}
if [ $# -lt 1 ]; then help; fi
#總任務數量
nJobs=4671
nSlots=${2:-8}
#設定工作目錄
WORK_PATH=`pwd`
#設定工作腳本
work_script=$1
#actor下載地址
URL_ACTOR="https://www.meituri.com/t"
URL=$URL_ACTOR
#中斷退出標志變量
exit_flag=0
#臨時測試變量
flag=0
flag_set=1
exit_generate(){
if [ $exit_flag -eq 1 ]; then
echo "檢測到重復操作,強制退出,會丟失保存數據"
exit 1
fi
exit_flag=1
echo "保存配置文件"
echo "flag=$flag flag_set=$flag_set cjob=$cjob nJobs=$nJobs" > config.ini
echo "等待子線程結束..."
while [ ${finish} -eq 0 ]; do
finish=1
idx=1
while [ ${idx} -le ${nSlots} ]; do
if [ -f $$_lock_${idx}.lck ]; then
finish=0
jobsDump ${idx}
else
rm -f "$$_dump_${idx}.dmp"
jobsDump ${idx} "本線程任務已結束..."
fi
idx=$((idx + 1))
done
sleep 1
done
echo "所有子線程已經全部結束,正常退出!"
exit 1
}
exit_2(){
echo "捕獲中斷信號:SIGINT"
exit_generate
}
exit_15(){
echo "捕獲中斷信號:SIGTERM"
exit_generate
}
#設置中斷捕獲響應
trap exit_2 2
trap exit_15 15
jobsInit()
{
clear
echo "$1"", ${nSlots} downloader"
idx=1
while [ $idx -le ${nSlots} ]; do
printf "\033[01;34mSlot %2d:\033[00m " $idx
idx=$((idx + 1))
done
}
jobsDump()
{
printf "\033[01;34mSlot %2d:\033[00m `date +%H:%M:%S` " $1
if [ -f $$_dump_$1.dmp ]; then
echo "`head -n1 $$_dump_$1.dmp`"
elif [ v"$2" != "v" ]; then
echo "$2"
fi
}
jobsInfo()
{
echo $*
}
if [ -f config.ini ]; then
echo "讀取配置文件,恢復上一次的下載記錄"
. ./config.ini
else
# clean dir
rm -rf Downloads
rm -f weblinklist.txt
cjob=0
fi
# Process jobs
finish=0
jobs_name="任務"
while [ ${finish} -eq 0 ]; do
jobsInfo "正在處理 ${cjob}/${nJobs} $jobs_name..."
finish=1
idx=1
while [ ${idx} -le ${nSlots} ]; do
if [ -f $$_lock_${idx}.lck ]; then
finish=0
jobsDump ${idx}
else
rm -f "$$_lock_${idx}.lck" "$$_dump_${idx}.dmp"
jobsDump ${idx} "空閑."
if [ ${cjob} -lt ${nJobs} ]; then
finish=0
#這里調度工作腳本,可以在這前面寫邏輯生成調度腳本的參數
#這里通過新開shell來執行,防止調度腳本被中斷后工作腳本一同遭殃
sh $work_script $$ ${idx} "$$_lock_${idx}.lck" "$$_dump_${idx}.dmp" $WORK_PATH $flag $URL $flag_set &
#創建/更新目錄鎖文件
#touch "$$_lock_${idx}.lck";
# Dump process info
jobsDump ${idx} "已分配任務,工作中..."
cjob=$((cjob + 1))
fi
fi
idx=$((idx + 1))
done
sleep 1
done
echo "所有任務已完成"
#刪除創建的所有臨時文件
rm -f $$_*
調度腳本主要負責調度用於執行真正工作任務的工作腳本,同時承擔向工作腳本傳不同的參數來向工作腳本下發不同的任務。
本腳本在原有參考的基礎上進行了改進,新增中斷捕獲(兩次中斷強制退出),可以在結束任務的時候依舊保證各工作腳本的工作不被打斷,同時監控各工作腳本的運行情況,此時不會再下發新任務,同時會保存當前的工作記錄,可用於下一次啟動的恢復上次工作的位置;修改了鎖文件創建的邏輯,由被調度腳本創建並自行銷毀,解決捕獲中斷可能造成的鎖文件存在但工作任務未被調度的情況。
二、工作腳本
#!/bin/sh # dowork.sh # 調用方法和參數總結 # 該腳本被multi.sh調用執行,傳遞給腳本7-8個參數 # param 1: PID of multi.sh # param 2: slot number # param 3: lock file name # param 4: info file name # param 5: working dir # param 6: working flag (set 0 to actorParser, set 1 to downloadParser) #創建線程鎖文件,標識線程運行態 touch "$3"; #配置文件 #wget下載參數配置 #重試次數:5,超時時間:5 tries=5 timeout=5 #宏參量定義 output=`pwd`/$4 #配置文件結束 #主程序起始點
#向output輸出的信息可以被調度腳本所打印 echo "子進程接受下發任務,准備處理,工作標志flag=$6" > $output # 在這上面可以寫該腳本需要完成命令 echo "$2當前任務執行完畢,退出" > $output # 腳本運行完了,在這里將鎖文件刪除,multi.sh就可以知道該腳本執行完畢了 rm -f $3
該腳本用於接受來自調度腳本下發的任務並運行,通過創建的info文件向調度腳本實時匯報自身工作狀態。
