图文记录下shell多进程
虽说shell的多进程是后台执行,但是学会了再写一些脚本的时候非常方便
先看传统的后台多进程方式,写个shell来举例
先是正常的运行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| [root@guan ~] > > start=`date +%s` > for i in `seq 10`;do > echo $i;sleep 2 > done > echo 'Time:' "$((`date +%s`-start))" > eof [root@guan ~] 1 2 3 4 5 6 7 8 9 10 Time: 20 [root@guan ~]
|
然后是后台运行来节约时间
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| [root@guan ~] > > start=`date +%s` > for i in `seq 10`;do > { echo $i;sleep 2; }& > done > wait > echo 'Time:' "$((`date +%s`-start))" > EOF [root@guan ~] 1 2 5 6 7 9 4 8 3 10 Time: 2 [root@guan ~]
|
从上面结果对比发现时间大大缩短,但是缺点是不能控制数量
然后因为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
| [root@guan ~]
max_process=5; start=`date +%s` for i in `seq 10`;do { echo $i;sleep 2; }& ((count++));((do_count++)) [ "$do_count" -eq '10' ] && { wait;break; }
[ "$count" -eq "$max_process" ] && { wait;count=0; } done echo 'Time:' "$((`date +%s`-start))" EOF [root@guan ~] 1 2 4 5 3 6 7 10 9 8 Time: 4 [root@guan ~]
|
这种还要考虑需要并发的进程数量在总次数下是否有余数的可能,后面我发现了可以用mkfifo来实现并发,代码更容易懂
无名管道: 就是我们经常使用的 例如: netstat -antp | grep "abc"
那个|
就是管道,只不过是无名的,可以直接作为两个进程的数据通道
有名管道: mkfilo
可以创建一个管道文件 ,例如: mkfifo fifo_file
管道有一个特点,如果管道中没有数据,那么取管道数据的操作就会停滞,直到
管道内进入数据,然后读出后才会终止这一操作,同理,写入管道的操作
如果没有读取操作,这一个动作也会停滞。
当我们试图用echo想管道文件中写入数据时,由于没有任何进程在对它做读取操作,所以
它会一直停留在那里等待读取操作,此时我们在另一终端上用cat指令做读取操作
你会发现读取操作一旦执行,写入操作就可以顺利完成了,同理,先做读取操作也是一样的(不信可以自行测试)
后面发现的多进程就是利用管道的读写来控制,exec绑定文件操作符重定向
exec绑定文件操作符后我们来试试按行读取会有啥现象
1 2 3 4 5 6 7 8 9 10
| [root@guan ~] [root@guan ~] [root@guan ~] [root@guan ~] ^C [root@guan ~] [root@guan ~] [root@guan ~] [root@guan ~] ^C
|
管道来并发控制就是先在管道里写入要并发数量的行数
每次read一行后后面把要后台的任务用大括号包起来后台了
然后大括号里面的最后一句是向管道里写入一行,只有后台任务执行完了下一个read -u才不会停滞
举个例子3条任务,并发数量为2,一开始管道里写入2行
然后下面代码
1 2 3 4 5 6 7 8 9 10 11 12
| mkfifo test_fifo exec 5<>test_fifo rm -f test_fifo seq 2>&5 for i in {1..3};do read -u5 { echo $i;sleep 2; echo >&5 }& done wait
|
脑补下执行过程,进入循环中:
第一次read(管道里有2行)不会被停滞,管道剩下1行,大括号里的所有代码放在后台(一个后台并发)
第二次read(管道里有1行)不会被停滞,管道剩下0行,大括号里的所有代码放在后台(俩个后台并发)
第三次read(管道里有0行),会被停滞,只有等一个后台执行完了(后台里最后一句)向管道里写入了一个空行,此次的read才会退出停滞状态后面的代码才能继续执行
然后循环结束后最后还有第三次的后台(此处不一定只有第三次的后台,可能第二次后台也没执行完),此处写个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 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| [root@guan ~] 1 2 3 trap 'exec 5>&-;exec 5<&-;exit 0' 2 4 5 max_process=$1 6 7 pipe=`mktemp -u tmp.XXXX` 8 mkfifo $pipe 9 exec 5<>$pipe 10 rm -f $pipe 11 12 seq $max_process>&5 13 14 start=`date +%s` 15 for i in {1..10};do 16 read -u5 17 { 18 echo $i;sleep 2; 19 echo >&5 20 }& 21 done 22 wait 23 echo 'Time:' "$((`date +%s`-start))" 24 25 exec 5>&-;exec 5<&- [root@guan ~] 1 2 3 4 5 6 7 8 9 10 Time: 10 [root@guan ~] 1 2 4 6 7 9 8 5 3 10 Time: 4 [root@guan ~]
|