那么shell并发该如何实现呢?
还是以例子来作讲解:
每次任务都是输出字符“bingfa”,并停留一秒钟,共20次。
按照正常思维,脚本应该这样写:
复制代码 代码如下:
[root@station1 ~]# cat a.sh
#!/bin/bash
for((i=0;i<20;i++))
do
sleep 1
echo "bingfa"
done
[root@station1 ~]# time bash a.sh
bingfa
bingfa
bingfa
bingfa
bingfa
bingfa
bingfa
bingfa
bingfa
bingfa
bingfa
bingfa
bingfa
bingfa
bingfa
bingfa
bingfa
bingfa
bingfa
bingfa
real 0m20.067s
user 0m0.016s
sys 0m0.031s
[root@station1 ~]#
可以看到执行此脚本大概用了20秒。那么使用shell并发该怎么写,很多人都会想到后台程序,类似如下:
复制代码 代码如下:
[root@station1 ~]# cat b.sh
#!/bin/bash
for((i=0;i<20;i++))
do
{
sleep 1
echo "bingfa"
}&
done
wait
[root@station1 ~]# time bash b.sh
bingfa
bingfa
bingfa
bingfa
bingfa
bingfa
bingfa
bingfa
bingfa
bingfa
bingfa
bingfa
bingfa
bingfa
bingfa
bingfa
bingfa
bingfa
bingfa
bingfa
real 0m1.060s
user 0m0.005s
sys 0m0.057s
[root@station1 ~]#
这样写只需花大概一秒钟,可以看到所有的任务几乎同时执行,如果任务量非常大,系统肯定承受不了,也会影响系统中其他程序的运行,这样就需要一个线程数量的控制。下面是我一开始写的代码(是有问题的):
复制代码 代码如下:
[root@station1 ~]# cat c.sh
#!/bin/bash
exec 6<>tmpfile
echo "1n1n1" &>6
for((i=0;i<20;i++))
do
read -u 6
{
sleep 1
echo "$REPLY"
echo "1" 1>&6
}&
done
wait
[root@station1 ~]# time bash c.sh
111
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
real 0m1.074s
user 0m0.012s
sys 0m0.031s
[root@station1 ~]#
可以明显看出是有问题的,我本想控制线程个数为3,但是就算文件描述符6中为空,也会被读取空,然后跳过继续下面的执行,所以使用文件描述符打开一个文件是不行的,然后我就想着使用类似管道的文件来做,下面是我的代码:
复制代码 代码如下:
[root@station1 ~]# cat d.sh
#!/bin/bash
mkfifo fd2
exec 9<>fd2
echo -n -e "1n1n1n" 1>&9
for((i=0;i<20;i++))
do
read -u 9
{ #your process
sleep 1
echo "$REPLY"
echo -ne "1n" 1>&9
} &
done
wait
rm -f fd2
[root@station1 ~]# time bash d.sh
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
real 0m7.075s
user 0m0.018s
sys 0m0.044s
[root@station1 ~]#
这样就可以了,三个线程运行20个任务,7秒多点。