脊柱结核

首页 » 常识 » 预防 » Shell脚本实现并发多进程了解一下
TUhjnbcbe - 2021/1/12 6:28:00
治疗效果好的白癜风医院         http://m.39.net/pf/bdfyy/xwdt/

来自:CU技术社区(13)

从事Linux主机建设和运维的同事们在工作中应该经常会遇到批量修改配置信息或部署应用环境的需求,需要根据需求依次登录目标主机执行一些命令或脚本,使用shll脚本的循环语句是实现这一需求最直观方式。但是普通的for或dowhil循环都是串行执行的,脚本耗时每个循环耗时*循环次数,在较大规模实施或者目标语句耗时较长的情况下,串行方式的循环脚本执行时间也不容忽视。

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

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

根据这个思路来看一下例1:

1例1直接使用后台执行

先来看下循环串行执行的情况。

脚本的循环内容以slp为例,下同。

vipara-0.sh

#!/bin/bash

Njob=15#任务总数

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

{

cho"progrss$iisslpingfor3scondszzz…"

slp3

}

don

cho-"tim-consuming:$SECONDSsconds"#显示脚本执行耗时

运行结果如下图所示:

可以看到脚本执行时间45秒与预期15轮*3秒一致。

如果打开另一个窗口watchslp进程的话,可以看到同一时刻只有1个slp进程在跑:

修改脚本,采用循环并行执行的方式。

vipara-1.sh

#!/bin/bash

Njob=15

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

cho"progrss$iisslpingfor3scondszzz…"

slp3#循环内容放到后台执行

don

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

cho-"tim-consuming:$SECONDSsconds"#显示脚本执行耗时

运行结果如下图所示:

可以看到脚本执行耗时为3秒,与预期1轮*3秒一致。

watchslp进程,可以看到同一时刻有15个PPID相同的slp进程在跑:

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

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

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

下面的例2和例3能够有效避免这些问题。

2例2使用模拟队列来控制进程数量

要控制后台同一时刻的进程数量,需要在原有循环的基础上增加管理机制。

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

运行结果如下图所示:

可以看到脚本执行时间9秒与预期3轮*3秒一致。

watchslp进程,可以看到同一时刻只有5个slp进程在跑,与我们限制的数量相符:

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

3例3使用fifo管道特性来控制进程数量

管道是内核中的一个单向的数据通道,同时也是一个数据队列。具有一个读取端与一个写入端,每一端对应着一个文件描述符。

命名管道即FIFO文件,通过命名管道可以在不相关的进程之间交换数据。FIFO有路径名与之相关联,以一种特殊设备文件形式存在于文件系统中。

FIFO有两种用途:

?FIFO由shll使用以便数据从一条管道线传输到另一条,为此无需创建临时文件,常见的操作catfil

grpkyword就是这种使用方式;

?FIFO用于客户进程-服务器进程程序中,已在客户进程与服务器进程之间传送数据,下面的例子将使用这种方式。

根据FIFO文件的读规则(参考

1
查看完整版本: Shell脚本实现并发多进程了解一下