当我们在执行一个for循环时,假设这个for循环需要循环500次,每循环一次就需要1秒,当这个for循环的脚本执行完毕时,就需要500秒,这样看效率有些低(尤其在量级高的时候,会更明显),所以我们需要shell脚本的for循环无论循环多少次,让它们同时执行,不需要按顺序循环,这就是shell脚本的并发。
2、如何实现shell脚本并发:
实现非常简单,就是在循环体的{}后面加上一个&符号,代表每次循环体的命令都放入后台运行
3、经典实例:
判断192.168.80.0/24网络,当前在线的主机数以及IP
#!/bin/bash
. /etc/init.d/functions
cmd="ping -c 2"
for ((i=1;i<=254;i++));do
{
$cmd 192.168.80.$i &>/dev/null
if [ $? = 0 ];then
action "192.168.80.$i" /bin/true
fi
}& #将{}循环体放入后台执行
done
wait #等待上面放入后台的命令执行完毕后,在往下执行(如果后面还有要执行的命令,最好加上wait),因为命令一旦放到后台执行,这条任务就交个操作系统了,shell脚本会不等上面的执行完毕,就会继续往下执行。
扩展知识点:
我们知道了什么是shell脚本的并发,试想一下,如果此时有1000个任务并发,就会有1000个线程产生,如果系统的资源跟不上,就会让计算机系统产生很大的压力,导致操作系统处理的速度会越来越慢。而此时我们又当如何解决呢?出现这个情况时,我们可以引入命名管道文件来处理。
命名管道处理的思路:
就相当于此时有10个开水房间,配有10把钥匙,此时有100个人要打开水,那么前10个人抢到钥匙,就先进去打开水,后面的90个人就需要等前面一个人出来后还回钥匙,在拿着钥匙进去打开水,这样就能控制100个人打开水的任务,同时不会将系统的资源一次性耗用太多,增加压力,减小处理速度。
知识点:
1、命名管道的特性
如果管道内容为空,则阻塞
管道具有读一个少一个,存一个读一个的性质,放回去的可以重复取
可以实现队列控制
2、如果管道放一段内容没有人取,则会阻塞
解决上述问题,可以通过文件描述符
文件描述符具有管道的所有特性,同时还具有一个管道不具有的特性:无限存不阻塞,无限取不阻塞,无需关注管道内容
创建方式:
1、创建命名管道mkfifo /tmp/fl
2、创建文件描述符100,并关联到管道文件exec 100<>/tmp/fl
3、调用文件描述符,向管道里存放内容,同时也表示将用完的管道内容在放回管道echo >&100
4、读取文件描述符关联管道中的内容
`read -u100``
5、关闭文件描述符的读和写
exec 100<&-
exec 100>&-
实例演示:引用上面的网络测试案例
#!/bin/bash
. /etc/init.d/functions
cmd="ping -c 2"
mkfifo /tmp/fl
exec 100<>/tmp/fl
rm -rf /tmp/fl
for ((n=1;n<=100;n++));do
echo >&100
done
for ((i=1;i<=254;i++));do
read -u100
{
$cmd 192.168.80.$i &>/dev/null
if [ $? = 0 ];then
echo "192.168.80.$i is ok"
else
echo "192.168.80.$i is no"
fi
echo >&100 #将管道内容在放回去
}&
done
wait
#echo "test compelet"
exec 100<&-
exec 100>&-