码迷,mamicode.com
首页 > 系统相关 > 详细

Linux-Shell-使用mkfifo实现多任务并发及并发数控制

时间:2019-12-27 09:33:55      阅读:124      评论:0      收藏:0      [点我收藏+]

标签:++   大量   exec   描述符   div   消费者   nat   blog   print   

默认的情况下,Shell脚本中的命令是串行执行的,必须等到前一条命令执行完后才执行接下来的命令,但是如果我有一大批的的命令需要执行,而且互相又没有影响的情况下(有影响的话就比较复杂了),那么就要使用命令的并发执行了。

如下:

#!/bin/bash
IPLIST=/home/meta/ipinfo/iplist
for i in $(cat ${IPLIST} |grep -viE "^#|备机|ts"|awk {print $1})
do
ssh $i "cd ~/update/;tar zxf patch-20160909.tgz -C ~/LMDG/ && echo ‘/$i ok‘ || echo ‘/$i bad‘"
done >> result.txt

echo "resutl"|mutt -a result.txt -s update-result meta@126.com

 

对于上面的代码,因为 iplist 中有好多ip,每个”tar zxf”都挺耗时的,所以打算使用并发编程,这样就可以节省大量时间了。

修改如下:

#!/bin/bash
IPLIST=/home/meta/ipinfo/iplist
for i in $(cat ${IPLIST} |grep -viE "^#|备机|ts"|awk {print $1})
do
ssh $i "cd ~/update/;tar zxf patch-20160909.tgz -C ~/LMDG/ && echo ‘/$i ok‘ || echo ‘/$i bad‘" &
done >> result.txt

echo "resutl"|mutt -a result.txt -s update-result meta@126.com

 

加上“&” 之后 “tar zxf”就可以并行执行了。 实质是将”tar zxf” 作为后台进程在执行,这样该命令就不会占用当前bash,其他命令也不用等待前面命令执行完再继续了,而且可以放入多个任务到后台,这样就实现了多任务并发。

我本来目的是让”tar zxf”这个循环都执行结束后,再“mutt”前面的结果。如果像上面这样写的话,在”tar zxf”都还没结束时就已经开始执行“mutt”了,得到了错误的结果,因此需要做如下修改:

#!/bin/bash
IPLIST=/home/meta/ipinfo/iplist
for i in $(cat ${IPLIST} |grep -viE "^#|备机|ts"|awk {print $1})
do
ssh $i "cd ~/update/;tar zxf patch-20160909.tgz -C ~/LMDG/ && echo ‘/$i ok‘ || echo ‘/$i bad‘" &
done >> result.txt
wait
echo "resutl"|mutt -a result.txt -s update-result meta@126.com

 

这里添加了“wait” 之后就可以达到我们预期的效果了,wait的作用就是等待子任务都执行完之后在结束父任务,继而执行下面的任务。

但是,紧接着又有问题了,如果这个iplist中的量巨大,这样一口气都放到后台,系统超出负载后,会有性能变差或者宕机风险,因此我们需要一个控制并发数的机制。
因此我们引入了任务队列的概念,有点类似之前socket举例中的消费者生产者模型,通过消息队列来调节供需的不平衡
修改如下:

#!/bin/bash

IPLIST=/home/meta/ipinfo/iplist #任务(消费者)
THREAD=50 #声明并发线程并发个数,这个是此应用的关键,也就是设置管道的最大任务数
TMPFIFO=/tmp/$$.fifo    #声明管道名称,$$表示脚本当前运行的进程PID
mkfifo $TMPFIFO #创建管道
exec 5<>${TMPFIFO} #创建文件标示符“5”,这个数字可以为除“0”、“1”、“2”之外的所有未声明过的字符,以读写模式操作管道文件;系统调用exec是以新的进程去代替原来的进程,但进程的PID保持不变,换句话说就是在调用进程内部执行一个可执行文件
rm -rf ${TMPFIFO} #清除创建的管道文件

#为并发线程创建同样个数的占位
for((i=1;i<=$THREAD;i++))
do
echo ; 
#借用read命令一次读取一行的特性,使用一个echo默认输出一个换行符,来确保每一行只有一个线程占位;这里让人联想到生产者&消费者模型,管道文件充当消息队列,来记录消费者的需求,然后由生产者去领任务,并完成任务,这里运用了异步解耦的思想。
done >&5 
#将占位信息写入管道

for i in $(cat ${IPLIST} |grep -viE "^#|备机|ts"|awk {print $1}) #从任务队列中依次读取任务
do
read -u5 
#从文件描述符管道中,获取一个管道的线程占位然后开始执行操作;read中 -u 后面跟fd,表示从文件描述符中读入,该文件描述符可以是exec新开启的。
{
echo $(cat ~/ipinfo/iplist|grep $i|awk {print $2});
ssh -oConnectTimeout=10 -oConnectionAttempts=3 $i "cd /home/Log/;grep ‘MIL‘ mission_2016-08-03*.log |awk -F, ‘{if(\$19==1370) print \$0}‘|
awk -F, {if(\$20==0) print \$0}>miss_info.txt"
echo "" >&5 
#任务执行完后在fd5中写入一个占位符,以保证这个线程执行完后,线程继续保持占位,继而维持管道中永远是50个线程数,&表示该部分命令/任务放入后台不占当前的bash,实现并行处理
} &
done
wait #等待父进程的子进程都执行结束后再结束父进程 
exec 5>&- #关闭fd5的管道
exit 0

 

————————————————
版权声明:本文为CSDN博主「白金牧场」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_34409701/article/details/52488964

Linux-Shell-使用mkfifo实现多任务并发及并发数控制

标签:++   大量   exec   描述符   div   消费者   nat   blog   print   

原文地址:https://www.cnblogs.com/cangqinglang/p/12105399.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!