阅读 100

Shell 中利用FIFO实现多进程tar解压的方法

上文Shell中使用tar命令批量解压缩的实现方法中提到我使用循环的方法批量解压tar文件,但是单进程的解压耗时太长,需要优化,故决定采用FIFO(有名管道)实现可控并发数的多进程解压。

需要直接知道解决方案的请看第二节

1.FIFO(有名管道)简述

FIFO,又称作命名管道(named pipe),它是Linux中用于进程间通信的一种方法。 FIFO是一种特殊的文件。由于linux所有的事物都可以被视为文件,所以对命名管道的使用也就变得与文件操作非常统一。 FIFO简单理解,就是它能把两个不相关的进程联系起来,FIFO就像一个公共通道,解决了不同进程之间的“代沟”。普通的无名管道只能让相关的进程进行沟通(比如父shell和子shell之间)。

下面模拟了一个FIFO通信的过程,主要有两个进程:

#!/bin/bash
#Client.sh
#不断向fifo写入数据

tmp_fifo="/tmp/test.fifo"
rm -f $tmp_fifo
mkfifo $tmp_fifo
exec 6<>$tmp_fifo #这句话能把管道变成非阻塞!

i=0
while :
do
	sleep 1                 # 1秒写一次
	echo "$i" >&6
        echo "$i"    
        #输出到终端的时候要小心,会覆盖你的终端,所以要停止,最好直接挂起进程!!
	let i++
done 

exec 6>&-
复制代码
#!/bin/bash
#Server.sh
#不断从fifo中读出数据

tmp_fifo="/tmp/test.fifo"
echo "$tmp_fifo"
exec 6<>$tmp_fifo                 #建立一个绑定

while :
do
        read TEXT
	sleep 1
	echo "$TEXT"          #每1s就读取一个数据,并且打印到终端,要停止,最好挂起进程!
done <&6

复制代码

打开终端A:$ ./Client.sh

打开终端B:$./Server.sh

你就能看到在终端B中从fifo中读取到的数据,你要是在终端B中把每次读fifo的间隔给改成2秒,就更能说明问题了。上面的程序,在实验的时候最好通过不断挂起A进程来查看,然后观察B进程的输出。你会知道FIFO整个是怎么跑的。。。

FIFO的出现,极好地解决了系统在应用过程中产生的大量的中间临时文件的问题。FIFO可以被shell调用使数据从一个进程到另一个进程,系统不必为该中间通道去烦恼清理不必要的垃圾,或者去释放该通道的资源,它可以被留做后来的进程使用。并且规避了匿名管道在作用域的限制,可应用于不相关的进程之间。

此节参考文章:blog.csdn.net/firefoxbug/…

2.利用FIFO实现多进程tar解压

#获取类型(Http等),目录地址,临时方案
type=$1
dir=$2
#获取时间,包括月、日、小时账期
#测试使用-调度内采用Oracle导入时间参数  
v_month=`date -d "-1 month" '+%Y%m'` #当月
echo $v_month
v_day=`date '+%Y%m%d'` #当日
echo $v_day
#v_hour=`date -d "-1 hour" '+%Y%m%d%H'` #前一个小时
echo $v_hour

#创建临时文件夹
temp='temp_'${type}'_'${v_hour}
echo ${temp}
mkdir ${dir}/${temp}

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

#为并发线程创建同样个数的占位
for((i=1;i<=$THREAD;i++))
do
   echo ;  
 #借用read命令一次读取一行的特性
 #使用一个echo默认输出一个换行符,来确保每一行只有一个线程占位
done >&5        #将占位信息写入管道         

#解压数据 匹配对应类型type和时间戳
for i in `ls ${dir}/*${v_hour}*${type}*`
do 
  #从文件描述符管道中,获取一个管道的线程占位然后开始执行操作;
#read中 -u 后面跟fd,表示从文件描述符中读入,该文件描述符可以是exec新开启的。
  read -u 5
  {
    tar -xzvf $i -C ${dir}/${temp}  #执行压缩 
#任务执行完后在fd5中写入一个占位符,以保证这个线程执行完后,线程继续保持占位
#继而维持管道中永远是固定线程数,&表示该部分命令/任务放入后台不占当前的bash,实现并行处理
    echo "" >&5 
  }&
done 

#等待前面的线程执行
wait  

exec 5>&-  #关闭fd5的管道
复制代码

此节参考文章:blog.csdn.net/qq_34409701…

关注下面的标签,发现更多相似文章
评论