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

利用命名管道实现并行。
mkfifo 创建FIFO(也称为"命名管道")."FIFO"是一种特殊的文件类型,它允许独立的进程通讯. 一个进程打开FIFO文件进行写操作,而另一个进程对之进行读操作,然后数据便可以如同在shell或者其它地方常见的的匿名管道一样流线执行.

实验:模拟任务沉睡一秒输出一次success,开20并行统计用时。

 !/bin/bash
 #set -x
 #开始时间
 start_time=date +%s  
 #声明并发线程并发个数,这个是此应用的关键,也就是设置管道的最大任务数,根据实际情况调节任务数,避免并行任务过多服务器宕机。
 thread=20  
 #创建命名管道,'$$'表示脚本当前运行的进程PID
 [ -e ./tmp/$$.fifo ] || mkfifo ./tmp/$$.fifo
 #创建文件标示符“3”,这个数字可以为除“0”、“1”、“2”之外的所有未声明过的字符,以读写模式操作管道文件;系统调用exec是以新的进程去代替原来的进程,但进程的PID保持不变,换句话说就是在调用进程内部执行一个可执行文件
 exec 3<> ./tmp/$$.fifo
#清除创建的管道文件
 rm -rf ./tmp/$$.fifo
# 为并发线程创建同样个数的占位
 for ((i=1;i<=20;i++)) do     echo >&3  #将占位信息写入管道
 done
 for ((i=1;i<=100;i++))
 do
 #从文件描述符管道中,获取一个管道的线程占位然后开始执行操作;read中 -u 后面跟fd,表示从文件描述符中读入,该文件描述符可以是exec新开启的。
 read -u3
# 模拟任务
 {
     sleep 1
     echo "success" $i
 #任务执行完后在fd3中重新写入一个占位符,以保证这个线程执行完后,线程继续保持占位,继而维持管道中永远是20个线程数,&表示该部分命令/任务放入后台不占当前的bash,实现并行处理
     echo >&3
 }&
 done
 wait #等待父进程的子进程都执行结束后再结束父进程          
 stop_time=date +%s
 echo " RUN TIME:expr $stop_time - $start_time"
 exec 3<&- #关闭fd3的管道 
 exec 3>&- #关闭fd3的管道 

完整shell代码,


#!/bin/bash
#set -x
start_time=date +%s
thread=20
[ -e ./tmp/$$.fifo ] || mkfifo ./tmp/$$.fifo
exec 3<> ./tmp/$$.fifo
rm -rf ./tmp/$$.fifo

for ((i=1;i<=$thread;i++))
do
        echo >&3
done

for ((i=1;i<=100;i++))
do
read -u3
{
        sleep 1
        echo "success" $i
        echo >&3
}&
done
wait

stop_time=date +%s

echo " RUN TIME:expr $stop_time - $start_time"

exec 3<&-
exec 3>&-

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据