shell多进程

shell中没有多进程的概念,可以通过开启子shell并在后台执行来实现并发。

    串行执行

#!/bin/bash
start=`date +"%s"`
for (( i=0; i<10; i++ ))
do
    {
        echo "execute"
        sleep 1
    }
done

end=`date +"%s"`
echo "time: " `expr $end - $start`
12
 
1
#!/bin/bash
2
start=`date +"%s"`
3
for (( i=0; i<10; i++ ))
4
do
5
    {
6
        echo "execute"
7
        sleep 1
8
    }
9
done
10
11
end=`date +"%s"`
12
echo "time: " `expr $end - $start`

    执行时间为10秒

    

    并发执行

    让for循环中的代码在后台子shell中执行,只需在for循环的结尾加上&,并且在for循环外加上wait语句,等待子进程结束即可。

#!/bin/bash
start=`date +"%s"`
for (( i=0; i<10; i++ ))
do
    {
        echo "execute"
        sleep 1
    }&
done
wait
end=`date +"%s"`
echo "time: " `expr $end - $start`
12
1
#!/bin/bash
2
start=`date +"%s"`
3
for (( i=0; i<10; i++ ))
4
do
5
    {
6
        echo "execute"
7
        sleep 1
8
    }&
9
done
10
wait
11
end=`date +"%s"`
12
echo "time: " `expr $end - $start`

    执行时间为1秒,速度提升了10倍。


    这种方式比较简单,但是有个弊端,无法控制子进程的数量,如果循环一万次,会产生一万个子进程,造成不可预期的情况。

    可以通过命名管道来控制子进程的数量

    管道可以用于进程间通信,一个进程向管道中写入数据,同时另一个进程从管道中读取数据,管道为空进程会被阻塞,只有一个进程读或者一个进程写管道时,进程也会被阻塞。

    通常使用的 cat | grep name 中的 | 是无名管道。

     

    利用命令管道控制并发数量的实例

#!/bin/bash

fd_fifo=/tmp/fd_1  
mkfifo $fd_fifo      #创建命令管道(pipe类型文件)
exec 6<>$fd_fifo     #将管道的fd与6号fd绑定
proc_num=5           #进程个数
count=0;
#预分配资源
for ((i=0;i<$proc_num;i++))
do
    echo >& 6        #写入一个空行
done

start=`date +"%s"
for (( i=0; i<10; i++ ))
do
  read -u 6          #读取一个空行
  {
      echo "execute"
      sleep 1
      echo >& 6      #完成任务,写入一个空行
  }&                 #后台执行
done
wait                 #等待所有的任务完成
exec 6>&-           #关闭fd 6描述符,stdou和stdin
exec 6<&-           
rm -f $fifo          #删除管道

end=`date +"%s"`
echo "time: " `expr $end - $start`
x
1
#!/bin/bash
2
3
fd_fifo=/tmp/fd_1  
4
mkfifo $fd_fifo      #创建命令管道(pipe类型文件)
5
exec 6<>$fd_fifo     #将管道的fd与6号fd绑定
6
proc_num=5           #进程个数
7
count=0;
8
#预分配资源
9
for ((i=0;i<$proc_num;i++))
10
do
11
    echo >& 6        #写入一个空行
12
done
13
14
start=`date +"%s"
15
for (( i=0; i<10; i++ ))
16
do
17
  read -u 6          #读取一个空行
18
  {
19
      echo "execute"
20
      sleep 1
21
      echo >& 6      #完成任务,写入一个空行
22
  }&                 #后台执行
23
done
24
wait                 #等待所有的任务完成
25
exec 6>&-           #关闭fd 6描述符,stdou和stdin
26
exec 6<&-           
27
rm -f $fifo          #删除管道
28
29
end=`date +"%s"`
30
echo "time: " `expr $end - $start`
执行时间为2秒(每次有5个进程在同时执行)

初始化向管道中写入5行空字符
父shell进程执行read -u 6,会从管道中读取一行,当管道为空时read -u会阻塞,保证最多只有5个shell进程在后台执行。
子shell进程执行echo >& 6,会向管道中写入一行,父shell进程阻塞状态解除,可以继续开启子shell执行任务。
父shell进程执行完10次循环后,调用wait函数,等待子shell执行完毕,回收资源。
如果不加上wait语句,父进程会直接退出,导致子进程成为孤儿进程(孤儿进程为被pid为1的init进程接管);或者子进程提前退出,父进程未执行完但不知道子进程的退出状态,会使子进程成为僵尸进程。

父进程的变量会被复制一份到子进程中,变量在子进程中的任何修改不会影响父进程中的变量。
原文地址:https://www.cnblogs.com/lolau/p/9647650.html