本隨筆主要講述在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文件向調度腳本實時匯報自身工作狀態。