bash命令并行

       在bash中,使用后台任务来实现任务的“多进程化”。在不加控制的模式下,不管有多少任务,全部都后台执行。也就是说,在这种情况下,有多少任务就有多少“进程”在同时执行。

实例一:正常情况脚本

1
2
3
4
5
6
7
8
9
10
#!/bin/bash

for ((i=0;i<5;i++));do
{
sleep 3;echo 1>>aa && echo "done!"
}
done
wait
cat aa|wc -l
rm aa

       这种情况下,程序顺序执行,每个循环3s,共需15s左右。

1
2
3
4
5
6
7
8
9
10
11
$ time bash test.sh 
done!
done!
done!
done!
done!
5

real 0m15.030s
user 0m0.002s
sys 0m0.003s

实例二:“多进程”实现

1
2
3
4
5
6
7
8
9
10
#!/bin/bash

for ((i=0;i<5;i++));do
{
sleep 3;echo 1>>aa && echo "done!"
}&
done
wait
cat aa|wc -l
rm aa

       这个实例实际上就在上面基础上多加了一个后台执行&符号,此时应该是5个循环任务并发执行,最后需要3s左右时间。

1
2
3
4
5
6
7
8
9
10
11
$ time bash test.sh 
done!
done!
done!
done!
done!
5

real 0m3.109s
user 0m0.008s
sys 0m0.100s

       效果非常明显。这里需要说明一下wait的左右。wait是等待前面的后台任务全部完成才往下执行,否则程序本身是不会等待的,这样对后面依赖前面任务结果的命令来说就可能出错。

       以上所讲的实例都是进程数目不可控制的情况,下面描述如何准确控制并发的进程数目。

**实例三:“多进程可控”实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#!/bin/bash

tmp_fifofile="/tmp/$$.fifo"
mkfifo $tmp_fifofile # 新建一个fifo类型的文件
exec 6<>$tmp_fifofile # 将fd6指向fifo类型
rm $tmp_fifofile
thread=15 # 此处定义线程数
for ((i=0;i<$thread;i++));do
echo
done >&6 # 事实上就是在fd6中放置了$thread个回车符


for ((i=0;i<50;i++));do # 50次循环
read -u6
# 一个read -u6命令执行一次,就从fd6中减去一个回车符,然后向下执行,
# fd6中没有回车符的时候,就停在这了,从而实现了线程数量控制

{ # 此处子进程开始执行,被放到后台
{sleep 3} && { echo "a_sub is finished"}

echo >&6 # 当进程结束以后,再向fd6中加上一个回车符,即补上了read -u6减去的那个
} &

done

wait # 等待所有的后台子进程结束
exec 6>&- # 关闭df6

exit 0

sleep 3s,线程数为15,一共循环50次,所以,此脚本一共的执行时间大约为12秒

即:
15x3=45, 所以 3x3s=9s
(50-45=5)<15, 所以1x3s=3s
所以9s+3s = 12s

1
2
3
4
5
$ time bash multithread.sh 

real 0m12.025s
user 0m0.020s
sys 0m0.064s

而当不使用多线程技巧的时候,执行时间为:50 x 3s = 150s。

注:此文转载自这里