一、使用场景

要减少执行串行循环的耗时,自然要考虑如何用并行方式解决。在shell之外有一些现成的管理部署工具如parallel、ansible、puppet、saltstack都能解决并发执行多任务的问题,但生产系统一般不允许随意安装新软件,因而我们这里只讨论不借助工具,只使用shell脚本如何实现并发执行多任务。

串行执行循环时,脚本中每一次循环对应的子进程都是脚本执行所处shell的前台进程,同一时间一个shell只能有一个前台进程,要做到并行执行多个进程,意味着脚本中的循环要放到执行环境shell的后台,作为后台进程去执行。

 

先看一个直接后台执行简单的并行任务脚本

#!/bin/bash

Njob=15

for ((i=0; i<$Njob; i++)); do

echo “progress $i is sleeping for 3 seconds zzz…”

sleep 3 & #循环内容放到后台执行

done

wait #等待循环结束再执行wait后面的内容

echo -e “time-consuming: $SECONDS seconds” #显示脚本执行耗时

执行:

可以看到用时3秒,与预期1轮*3秒一致。

这种方式从功能上实现了使用shell脚本并行执行多个循环进程,但是它缺乏控制机制。

for设置了Njob次循环,同一时间Linux就触发Njob个进程一起执行。假设for里面执行的是scp,在没有pam_limits和cgroup限制的情况下,很有可能同一时刻过多的scp任务会耗尽系统的磁盘IO、连接数、带宽等资源,导致正常的业务受到影响。

一个应对办法是在for循环里面再嵌套一层循环,这样同一时间,系统最多只会执行内嵌循环限制值的个数的进程。不过还有一个问题,for后面的wait命令以循环中最慢的进程结束为结束(水桶效应)。如果嵌套循环中有某一个进程执行过程较慢,那么整体这一轮内嵌循环的执行时间就等于这个“慢”进程的执行时间,整体下来脚本的执行效率还是受到影响的。

 

下面有两个方法来解决上面的问题,(队列和管道)

方法1.使用模拟队列来控制进程数量

脚本逻辑:

要控制后台同一时刻的进程数量,需要在原有循环的基础上增加管理机制。一个方法是以for循环的子进程PID做为队列元素,模拟一个限定最大进程数的队列(只是一个长度固定的数组,并不是真实的队列)。队列的初始长度为0,循环每创建一个进程,就让队列长度+1。当队列长度到达设置的并发进程限制数之后,每隔一段时间检查队列,如果队列长度还是等于限制值,那么不做操作,继续轮询;如果检测到有并发进程执行结束了,那么队列长度-1,轮询检测到队列长度小于限制值后,会启动下一个待执行的进程,直至所有等待执行的并发进程全部执行完。

#!/bin/bash

Cjob=15 #任务总数
Njob=3 #最大并发任务数

#将pid值追加到队列中
push_que(){
que=”$que $1″ #pid队列
Nrun=$(($Nrun+1)) #队列个数加1

}

#更新队列,先清空队列信息,然后检索生成新的队列信息
up_que(){
oldque=$que
que=””;Nrun=0
for PID in $oldque
do
if [[ -d /proc/$PID ]];then
push_que $PID
fi
done

}

#检查队列信息,若有已经结束的进程pid,那么更新队列信息
check_que(){
oldque=$que
for PID in $oldque
do
if [[ ! -d /proc/$PID ]];then #检查是否存在pid文件目录,不存在就update队列
up_que #更新队列
break #终止循环
fi
done
}

for ((i=1; i<=$Cjob; i++))
do
echo “progress $i is sleeping for 3 seconds zzz…”
sleep 3 & #循环内容放到后台执行
PID=$! #获取进程pid
push_que $PID
while [[ $Nrun -ge $Njob ]] #若队列值大于设定的最大并发任务数,就一直check队列信息
do
check_que
sleep 0.1
done

done

wait #等待循环结束再执行wait后面的内容

echo -e “time-consuming: $SECONDS seconds” #显示脚本执行耗时

运行结果如下图所示:

可以看到脚本执行时间16秒与预期5轮*3秒一致。其中多1秒是因为脚本检查的时候我sleep了0.1秒

这种使用队列模型管理进程的方式在控制了后台进程数量的情况下,还能避免个别“慢”进程影响整体耗时的问题。

 

方法2使用fifo管道特性来控制进程数量

略。

有兴趣的可以去原文看下,本文转载自http://www.sohu.com/a/240639277_700886

 

 

为Kubernetes v1.5.2版本安装dashboard图形界面

一、前言 dashboard是一个图形化管理界面,由于我这边的Kubernetes v1.5.2比较老,按官网的安装方法没有效果,现在试试手动安装,使用下面2个yaml文件安装 ...

阅读全文

k8s简单部署

K8s中文手册地址:https://www.kuboard.cn/learning/k8s-basics/kubernetes-basics.html#kubernetes%E5%8A%9F%E8%83%BD   这边安装的Kubernetes v1.5.2 比较...

阅读全文

centos7上openvpn搭建详细教程

写在前面的前言: 因为工作需要安全连接公司的内网机器。对比了几个vpn的配置及工作模式。安全性:openvpn>l2tp/ipsec>pptp ,当然还有ss+代理的模式。...

阅读全文

欢迎留言