本随笔主要讲述在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 " 33[01;34mSlot %2d: 33[00m " $idx idx=$((idx + 1)) done } jobsDump() { printf " 33[01;34mSlot %2d: 33[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文件向调度脚本实时汇报自身工作状态。